/**
 * eIDAS to Microsoft Entra VerifiedID Bridge
 * Connects eIDAS verification to Microsoft Entra VerifiedID for credential issuance
 */

import { EIDASProvider, EIDASSignature } from './eidas';
import { EntraVerifiedIDClient, VerifiableCredentialRequest, ClaimValue } from './entra-verifiedid';
import { AzureLogicAppsClient } from './azure-logic-apps';
import { validateBase64File, FILE_SIZE_LIMITS, encodeFileToBase64, FileValidationOptions } from './file-utils';

export interface EIDASToEntraConfig {
  entraVerifiedID: {
    tenantId: string;
    clientId: string;
    clientSecret: string;
    credentialManifestId: string;
  };
  eidas: {
    providerUrl: string;
    apiKey: string;
  };
  logicApps?: {
    workflowUrl: string;
    accessKey?: string;
    managedIdentityClientId?: string;
  };
}

export interface EIDASVerificationResult {
  verified: boolean;
  eidasSignature?: EIDASSignature;
  certificateChain?: string[];
  subject?: string;
  issuer?: string;
  validityPeriod?: {
    notBefore: Date;
    notAfter: Date;
  };
}

/**
 * Bridge between eIDAS verification and Microsoft Entra VerifiedID issuance
 */
export class EIDASToEntraBridge {
  private eidasProvider: EIDASProvider;
  private entraClient: EntraVerifiedIDClient;
  private logicAppsClient?: AzureLogicAppsClient;

  constructor(config: EIDASToEntraConfig) {
    this.eidasProvider = new EIDASProvider({
      providerUrl: config.eidas.providerUrl,
      apiKey: config.eidas.apiKey,
    });

    this.entraClient = new EntraVerifiedIDClient({
      tenantId: config.entraVerifiedID.tenantId,
      clientId: config.entraVerifiedID.clientId,
      clientSecret: config.entraVerifiedID.clientSecret,
      credentialManifestId: config.entraVerifiedID.credentialManifestId,
    });

    if (config.logicApps) {
      this.logicAppsClient = new AzureLogicAppsClient(config.logicApps);
    }
  }

  /**
   * Verify eIDAS signature and issue credential via Entra VerifiedID
   */
  async verifyAndIssue(
    document: string | Buffer,
    userId: string,
    userEmail: string,
    pin?: string,
    validationOptions?: FileValidationOptions
  ): Promise<{
    verified: boolean;
    credentialRequest?: {
      requestId: string;
      url: string;
      qrCode?: string;
    };
    errors?: string[];
  }> {
    // Step 0: Validate and encode document if needed
    let documentBase64: string;

    if (document instanceof Buffer) {
      // Encode buffer to base64
      documentBase64 = encodeFileToBase64(document);
    } else {
      // Validate base64 string
      const validation = validateBase64File(
        document as string,
        validationOptions || {
          maxSize: FILE_SIZE_LIMITS.MEDIUM,
          allowedMimeTypes: [
            'application/pdf',
            'image/png',
            'image/jpeg',
            'application/json',
            'text/plain',
          ],
        }
      );

      if (!validation.valid) {
        return {
          verified: false,
          errors: validation.errors,
        };
      }

      documentBase64 = document as string;
    }

    // Step 1: Request eIDAS signature
    let eidasSignature: EIDASSignature;
    try {
      eidasSignature = await this.eidasProvider.requestSignature(documentBase64);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      console.error('eIDAS signature request failed:', errorMessage);
      return {
        verified: false,
        errors: [`eIDAS signature request failed: ${errorMessage}`],
      };
    }

    // Step 2: Verify eIDAS signature
    const verified = await this.eidasProvider.verifySignature(eidasSignature);
    if (!verified) {
      return {
        verified: false,
        errors: ['eIDAS signature verification failed'],
      };
    }

    // Step 3: Trigger Logic App workflow if configured
    if (this.logicAppsClient) {
      try {
        const documentId = document instanceof Buffer ? document.toString('base64').substring(0, 100) : (document as string).substring(0, 100);
        await this.logicAppsClient.triggerEIDASVerification(
          documentId,
          userId,
          this.eidasProvider['config'].providerUrl
        );
      } catch (error) {
        console.warn('Logic App trigger failed (non-blocking):', error);
      }
    }

    // Step 4: Issue credential via Entra VerifiedID
    const credentialRequest: VerifiableCredentialRequest = {
      claims: {
        email: userEmail,
        userId,
        eidasVerified: true, // Boolean value (will be converted to string)
        eidasCertificate: eidasSignature.certificate,
        eidasSignatureTimestamp: eidasSignature.timestamp.toISOString(),
      },
      pin,
    };

    try {
      const credentialResponse = await this.entraClient.issueCredential(credentialRequest);

      return {
        verified: true,
        credentialRequest: {
          requestId: credentialResponse.requestId,
          url: credentialResponse.url,
          qrCode: credentialResponse.qrCode,
        },
      };
    } catch (error) {
      console.error('Entra VerifiedID credential issuance failed:', error);
      return { verified: true }; // eIDAS verified but credential issuance failed
    }
  }

  /**
   * Verify eIDAS signature only (without issuing credential)
   */
  async verifyEIDAS(document: string): Promise<EIDASVerificationResult> {
    try {
      const signature = await this.eidasProvider.requestSignature(document);
      const verified = await this.eidasProvider.verifySignature(signature);

      if (!verified) {
        return { verified: false };
      }

      // Extract certificate information (simplified - in production parse certificate)
      return {
        verified: true,
        eidasSignature: signature,
        subject: 'eIDAS Subject', // Would be extracted from certificate
        issuer: 'eIDAS Issuer', // Would be extracted from certificate
        validityPeriod: {
          notBefore: signature.timestamp,
          notAfter: new Date(signature.timestamp.getTime() + 365 * 24 * 60 * 60 * 1000), // 1 year default
        },
      };
    } catch (error) {
      console.error('eIDAS verification failed:', error);
      return { verified: false };
    }
  }

  /**
   * Issue credential based on verified eIDAS signature
   */
  async issueCredentialFromEIDAS(
    eidasVerificationResult: EIDASVerificationResult,
    userId: string,
    userEmail: string,
    additionalClaims?: Record<string, ClaimValue>,
    pin?: string
  ): Promise<{
    requestId: string;
    url: string;
    qrCode?: string;
  }> {
    if (!eidasVerificationResult.verified || !eidasVerificationResult.eidasSignature) {
      throw new Error('eIDAS verification must be successful before issuing credential');
    }

    const claims: Record<string, ClaimValue> = {
      email: userEmail,
      userId,
      eidasVerified: true, // Boolean value (will be converted to string)
      eidasCertificate: eidasVerificationResult.eidasSignature.certificate,
      eidasSignatureTimestamp: eidasVerificationResult.eidasSignature.timestamp.toISOString(),
      ...additionalClaims,
    };

    if (eidasVerificationResult.subject) {
      claims.eidasSubject = eidasVerificationResult.subject;
    }

    if (eidasVerificationResult.issuer) {
      claims.eidasIssuer = eidasVerificationResult.issuer;
    }

    const credentialRequest: VerifiableCredentialRequest = {
      claims,
      pin,
    };

    return await this.entraClient.issueCredential(credentialRequest);
  }
}

