/**
 * Automated credential revocation workflow
 */

import {
  revokeCredential,
  isCredentialRevoked,
  getVerifiableCredentialById,
  query,
  type VerifiableCredential,
} from '@the-order/database';
import { getEventBus, CredentialEvents, UserEvents } from '@the-order/events';

/**
 * Initialize automated revocation system
 */
export async function initializeCredentialRevocation(): Promise<void> {
  const eventBus = getEventBus();

  // Subscribe to user suspension events
  await eventBus.subscribe(UserEvents.SUSPENDED, async (data) => {
    const { userId: _userId, did } = data as { userId: string; did?: string };
    if (did) {
      await revokeAllUserCredentials(did, 'User account suspended');
    }
  });

  // Subscribe to role removal events
  await eventBus.subscribe('role.removed', async (data) => {
    const { userId: _userId, role, did } = data as { userId: string; role: string; did?: string };
    if (did) {
      await revokeRoleCredentials(did, role, 'Role removed');
    }
  });

  // Subscribe to security incident events
  await eventBus.subscribe('security.incident', async (data) => {
    const { credentialId, reason } = data as { credentialId: string; reason: string };
    await revokeCredentialBySecurityIncident(credentialId, reason);
  });
}

/**
 * Revoke credential due to security incident
 */
async function revokeCredentialBySecurityIncident(
  credentialId: string,
  reason: string
): Promise<void> {
  const eventBus = getEventBus();

  // Check if already revoked
  const alreadyRevoked = await isCredentialRevoked(credentialId);
  if (alreadyRevoked) {
    return;
  }

  // Get credential to retrieve issuer DID
  const credential = await getVerifiableCredentialById(credentialId);
  if (!credential) {
    console.error(`Credential ${credentialId} not found for revocation`);
    return;
  }

  // Revoke the credential
  await revokeCredential({
    credential_id: credentialId,
    issuer_did: credential.issuer_did,
    revocation_reason: `Security incident: ${reason}`,
    revoked_by: 'system',
  });

  // Publish revocation event
  await eventBus.publish(CredentialEvents.REVOKED, {
    credentialId,
    reason: `Security incident: ${reason}`,
    revokedAt: new Date().toISOString(),
  });
}

/**
 * Revoke all credentials for a user (by subject DID)
 */
export async function revokeAllUserCredentials(
  subjectDid: string,
  reason: string
): Promise<void> {
  const eventBus = getEventBus();

  // Get all credentials for this subject DID
  const result = await query<VerifiableCredential>(
    `SELECT * FROM verifiable_credentials 
     WHERE subject_did = $1 AND revoked = FALSE`,
    [subjectDid]
  );

  // Revoke each credential
  for (const credential of result.rows) {
    try {
      await revokeCredential({
        credential_id: credential.credential_id,
        issuer_did: credential.issuer_did,
        revocation_reason: reason,
        revoked_by: 'system',
      });

      // Publish revocation event
      await eventBus.publish(CredentialEvents.REVOKED, {
        credentialId: credential.credential_id,
        reason,
        revokedAt: new Date().toISOString(),
      });
    } catch (error) {
      console.error(`Failed to revoke credential ${credential.credential_id}:`, error);
    }
  }
}

/**
 * Revoke role-based credentials for a user
 */
export async function revokeRoleCredentials(
  subjectDid: string,
  role: string,
  reason: string
): Promise<void> {
  const eventBus = getEventBus();

  // Get role-based credentials (credentials that contain the role in their type)
  const result = await query<VerifiableCredential>(
    `SELECT * FROM verifiable_credentials 
     WHERE subject_did = $1 
       AND revoked = FALSE 
       AND credential_type @> $2::jsonb`,
    [subjectDid, JSON.stringify([role])]
  );

  // Revoke each role-based credential
  for (const credential of result.rows) {
    try {
      // Check if credential type includes the role
      const hasRole = credential.credential_type.some((type) =>
        type.toLowerCase().includes(role.toLowerCase())
      );

      if (hasRole) {
        await revokeCredential({
          credential_id: credential.credential_id,
          issuer_did: credential.issuer_did,
          revocation_reason: `${reason} (Role: ${role})`,
          revoked_by: 'system',
        });

        // Publish revocation event
        await eventBus.publish(CredentialEvents.REVOKED, {
          credentialId: credential.credential_id,
          reason: `${reason} (Role: ${role})`,
          revokedAt: new Date().toISOString(),
        });
      }
    } catch (error) {
      console.error(`Failed to revoke role credential ${credential.credential_id}:`, error);
    }
  }
}

