// E-Signature Integration Service
// Integration with DocuSign/HelloSign

import { retryWithBackoff } from '@/shared/utils/retry';
import { docusignCircuitBreaker } from '@/shared/utils/circuit-breaker';
import { logger } from '@/infrastructure/monitoring/logger';

export interface ESignatureRequest {
  agreementId: string;
  signers: Array<{
    name: string;
    email: string;
    role: 'dbis' | 'participant';
    order: number;
  }>;
}

export interface ESignatureResult {
  envelopeId: string;
  status: string;
  signerStatus: Array<{
    email: string;
    status: string;
    signedAt?: Date;
  }>;
}

export class ESignatureIntegration {
  private provider: 'docusign' | 'hellosign';

  constructor(provider: 'docusign' | 'hellosign' = 'docusign') {
    this.provider = provider;
  }

  /**
   * Create e-signature envelope
   */
  async createEnvelope(request: ESignatureRequest): Promise<ESignatureResult> {
    if (this.provider === 'docusign') {
      return this.createDocuSignEnvelope(request);
    } else {
      return this.createHelloSignEnvelope(request);
    }
  }

  /**
   * Get envelope status
   */
  async getEnvelopeStatus(envelopeId: string): Promise<ESignatureResult> {
    if (this.provider === 'docusign') {
      return this.getDocuSignStatus(envelopeId);
    } else {
      return this.getHelloSignStatus(envelopeId);
    }
  }

  /**
   * Create DocuSign envelope
   */
  private async createDocuSignEnvelope(request: ESignatureRequest): Promise<ESignatureResult> {
    const docusignApiBase = process.env.DOCUSIGN_API_BASE || 'https://demo.docusign.net/restapi';
    const docusignAccountId = process.env.DOCUSIGN_ACCOUNT_ID;
    const docusignAccessToken = process.env.DOCUSIGN_ACCESS_TOKEN;

    if (!docusignAccountId || !docusignAccessToken) {
      throw new Error('DOCUSIGN_ACCOUNT_ID and DOCUSIGN_ACCESS_TOKEN environment variables are required');
    }

    // Get agreement content
    const agreementContent = await this.getAgreementContent(request.agreementId);

    // Create envelope
    const envelope = {
      emailSubject: 'IRU Participation Agreement - Signature Required',
      documents: [
        {
          documentBase64: Buffer.from(agreementContent).toString('base64'),
          name: 'IRU Participation Agreement.pdf',
          fileExtension: 'pdf',
          documentId: '1',
        },
      ],
      recipients: {
        signers: request.signers.map((signer, index) => ({
          email: signer.email,
          name: signer.name,
          recipientId: (index + 1).toString(),
          routingOrder: signer.order.toString(),
          tabs: {
            signHereTabs: [
              {
                documentId: '1',
                pageNumber: '1',
                recipientId: (index + 1).toString(),
                xPosition: '100',
                yPosition: `${100 + index * 50}`,
              },
            ],
          },
        })),
      },
      status: 'sent',
    };

    const response = await docusignCircuitBreaker.execute(async () => {
      return await retryWithBackoff(
        async () => {
          return await fetch(`${docusignApiBase}/v2.1/accounts/${docusignAccountId}/envelopes`, {
            method: 'POST',
            headers: {
              'Authorization': `Bearer ${docusignAccessToken}`,
              'Content-Type': 'application/json',
            },
            body: JSON.stringify(envelope),
          });
        },
        {
          maxRetries: 3,
          initialDelayMs: 1000,
          onRetry: (attempt, error) => {
            logger.warn('DocuSign API retry', {
              attempt,
              error: error.message,
            });
          },
        }
      );
    });

    if (!response.ok) {
      throw new Error(`DocuSign API error: ${response.status} ${response.statusText}`);
    }

    const data = await response.json();

    return {
      envelopeId: data.envelopeId,
      status: data.status,
      signerStatus: request.signers.map((signer) => ({
        email: signer.email,
        status: 'awaiting_signature',
      })),
    };
  }

  /**
   * Get agreement content
   */
  private async getAgreementContent(agreementId: string): Promise<string> {
    // Fetch from database
    const { default: prisma } = await import('@/shared/database/prisma');
    
    const agreement = await prisma.iruAgreement.findUnique({
      where: { agreementId },
      select: { agreementContent: true },
    });

    if (agreement?.agreementContent) {
      return agreement.agreementContent;
    }

    // Fallback to default template if not found
    return 'IRU Participation Agreement content...';
  }

  /**
   * Get DocuSign status
   */
  private async getDocuSignStatus(envelopeId: string): Promise<ESignatureResult> {
    const docusignApiBase = process.env.DOCUSIGN_API_BASE || 'https://demo.docusign.net/restapi';
    const docusignAccountId = process.env.DOCUSIGN_ACCOUNT_ID;
    const docusignAccessToken = process.env.DOCUSIGN_ACCESS_TOKEN;

    if (!docusignAccountId || !docusignAccessToken) {
      throw new Error('DOCUSIGN_ACCOUNT_ID and DOCUSIGN_ACCESS_TOKEN environment variables are required');
    }

    const response = await docusignCircuitBreaker.execute(async () => {
      return await retryWithBackoff(
        async () => {
          return await fetch(
            `${docusignApiBase}/v2.1/accounts/${docusignAccountId}/envelopes/${envelopeId}`,
            {
              headers: {
                'Authorization': `Bearer ${docusignAccessToken}`,
              },
            }
          );
        },
        {
          maxRetries: 3,
          initialDelayMs: 1000,
        }
      );
    });

    if (!response.ok) {
      throw new Error(`DocuSign API error: ${response.status} ${response.statusText}`);
    }

    const data = await response.json();

    // Get recipient status
    const recipientsResponse = await docusignCircuitBreaker.execute(async () => {
      return await retryWithBackoff(
        async () => {
          return await fetch(
            `${docusignApiBase}/v2.1/accounts/${docusignAccountId}/envelopes/${envelopeId}/recipients`,
            {
              headers: {
                'Authorization': `Bearer ${docusignAccessToken}`,
              },
            }
          );
        },
        {
          maxRetries: 3,
          initialDelayMs: 1000,
        }
      );
    });

    const recipientsData = await recipientsResponse.json();
    const signerStatus = recipientsData.signers?.map((signer: any) => ({
      email: signer.email,
      status: signer.status,
      signedAt: signer.signedDateTime ? new Date(signer.signedDateTime) : undefined,
    })) || [];

    return {
      envelopeId,
      status: data.status,
      signerStatus,
    };
  }

  /**
   * Create HelloSign envelope
   */
  private async createHelloSignEnvelope(request: ESignatureRequest): Promise<ESignatureResult> {
    const { hellosignIntegration } = await import('./hellosign-integration.service');
    
    const result = await hellosignIntegration.createSignatureRequest({
      agreementId: request.agreementId,
      signers: request.signers,
    });

    return {
      envelopeId: result.signatureRequestId,
      status: result.status,
      signerStatus: result.signerStatus,
    };
  }

  /**
   * Get HelloSign status
   */
  private async getHelloSignStatus(envelopeId: string): Promise<ESignatureResult> {
    const { hellosignIntegration } = await import('./hellosign-integration.service');
    
    const result = await hellosignIntegration.getSignatureRequestStatus(envelopeId);

    return {
      envelopeId: result.signatureRequestId,
      status: result.status,
      signerStatus: result.signerStatus,
    };
  }
}

export const esignatureIntegration = new ESignatureIntegration();
