/**
 * Auto-Issuance Service
 * Listens to application.approved events and automatically issues credentials
 */

import { getEventBus } from '@the-order/events';
import { getEResidencyApplicationById, createVerifiableCredential, logCredentialAction } from '@the-order/database';
import { KMSClient } from '@the-order/crypto';
import { getEnv } from '@the-order/shared';
import { getNotificationService } from '@the-order/notifications';
import { randomUUID } from 'crypto';
import type { eResidentCredential } from '@the-order/schemas';
import { LevelOfAssurance, EvidenceType, EvidenceResult } from '@the-order/schemas';

export interface AutoIssuanceConfig {
  kmsClient: KMSClient;
  autoIssueOnApproval?: boolean;
}

/**
 * Initialize auto-issuance service
 */
export async function initializeAutoIssuance(config: AutoIssuanceConfig): Promise<void> {
  if (!config.autoIssueOnApproval) {
    return;
  }

  const eventBus = getEventBus();
  const env = getEnv();
  const issuerDid = env.DSB_ISSUER_DID || env.VC_ISSUER_DID || (env.DSB_ISSUER_DOMAIN ? `did:web:${env.DSB_ISSUER_DOMAIN}` : undefined);

  if (!issuerDid) {
    console.warn('DSB_ISSUER_DID or VC_ISSUER_DID not configured - auto-issuance disabled');
    return;
  }

  // Subscribe to application.approved events
  await eventBus.subscribe('application.approved', async (data) => {
    const eventData = data as {
      applicationId: string;
      applicantDid?: string;
      email: string;
      givenName: string;
      familyName: string;
    };

    try {
      // Get application from database
      const application = await getEResidencyApplicationById(eventData.applicationId);
      if (!application) {
        console.error(`Application ${eventData.applicationId} not found`);
        return;
      }

      // Issue credential
      await issueEResidentCredential(application, config.kmsClient, issuerDid);
    } catch (error) {
      console.error(`Failed to auto-issue credential for application ${eventData.applicationId}:`, error);
    }
  });
}

/**
 * Issue eResident credential
 */
async function issueEResidentCredential(
  application: {
    id: string;
    applicantDid?: string;
    email: string;
    givenName: string;
    familyName: string;
    kycResults?: unknown;
    sanctionsResults?: unknown;
    riskAssessment?: unknown;
  },
  kmsClient: KMSClient,
  issuerDid: string
): Promise<void> {
  // Generate resident number
  const residentNumber = `RES-${randomUUID().substring(0, 8).toUpperCase()}`;
  const credentialId = randomUUID();
  const issuanceDate = new Date();

  // Create credential
  const credential: eResidentCredential = {
    '@context': [
      'https://www.w3.org/2018/credentials/v1',
      'https://w3id.org/security/suites/ed25519-2020/v1',
      'https://dsb.example/context/base/v1',
      'https://dsb.example/context/eResident/v1',
    ],
    type: ['VerifiableCredential', 'eResidentCredential'],
    issuer: issuerDid,
    issuanceDate: issuanceDate.toISOString(),
    expirationDate: new Date(issuanceDate.getTime() + 365 * 24 * 60 * 60 * 1000).toISOString(), // 1 year
    credentialSubject: {
      id: application.applicantDid || `did:web:dsb.example:members:${residentNumber}`,
      legalName: `${application.givenName} ${application.familyName}`,
      assuranceLevel: LevelOfAssurance.LOA2,
      residentNumber,
      issueJurisdiction: 'DSB',
    },
    evidence: [
      {
        type: EvidenceType.DocumentVerification,
        result: EvidenceResult.pass,
        timestamp: issuanceDate.toISOString(),
      },
      {
        type: EvidenceType.LivenessCheck,
        result: EvidenceResult.pass,
        timestamp: issuanceDate.toISOString(),
      },
      {
        type: EvidenceType.SanctionsScreen,
        result: EvidenceResult.pass,
        timestamp: issuanceDate.toISOString(),
      },
    ],
    proof: {
      type: 'Ed25519Signature2020',
      created: issuanceDate.toISOString(),
      proofPurpose: 'assertionMethod',
      verificationMethod: `${issuerDid}#key-1`,
      jws: '', // Will be populated after signing
    },
  };

  // Sign credential
  const credentialJson = JSON.stringify(credential);
  const signature = await kmsClient.sign(Buffer.from(credentialJson));
  credential.proof.jws = signature.toString('base64');

  // Save to database
  await createVerifiableCredential({
    credential_id: credentialId,
    issuer_did: issuerDid,
    subject_did: credential.credentialSubject.id,
    credential_type: credential.type,
    credential_subject: credential.credentialSubject,
    issuance_date: issuanceDate,
    expiration_date: new Date(credential.expirationDate!),
    proof: credential.proof,
  });

  // Log audit action
  await logCredentialAction({
    credential_id: credentialId,
    issuer_did: issuerDid,
    subject_did: credential.credentialSubject.id,
    credential_type: credential.type,
    action: 'issued',
    performed_by: 'system',
    metadata: {
      applicationId: application.id,
      residentNumber,
      autoIssued: true,
    },
  });

  // Publish event
  const eventBus = getEventBus();
  await eventBus.publish('credential.issued', {
    credentialId,
    credentialType: 'eResidentCredential',
    residentNumber,
    issuedAt: issuanceDate.toISOString(),
  });

  // Send notification
  const notificationService = getNotificationService();
  await notificationService.send({
    to: application.email,
    type: 'email',
    subject: 'eResidency Credential Issued',
    message: `Your eResidency credential has been issued. Resident Number: ${residentNumber}`,
    template: 'eresidency-issued',
    templateData: {
      residentNumber,
      credentialId,
      issuedAt: issuanceDate.toISOString(),
      legalName: `${application.givenName} ${application.familyName}`,
    },
  });
}

