
import { PDFDocument, rgb, StandardFonts, PDFPage } from 'pdf-lib';
import crypto from 'crypto';

interface QuoteData {
  id: string;
  quoteNumber: string;
  clientName: string;
  clientEmail: string;
  clientCompany?: string;
  clientPhone?: string;
  clientAddress?: string;
  serviceName: string;
  serviceDescription?: string;
  lineItems?: any;
  total: number;
  subtotal: number;
  taxes?: number;
  discounts?: number;
  paymentTerms?: string;
  startDate?: string;
  validUntil?: string;
  notes?: string;
}

interface ContractMetadata {
  contractId: string;
  createdAt: Date;
  quoteId: string;
  clientName: string;
  totalAmount: number;
}

class PDFService {
  // Generate contract from quote data
  async generateContract(
    quoteData: QuoteData,
    contractNumber: string
  ): Promise<{ pdfBytes: Uint8Array; contractId: string; metadata: ContractMetadata }> {
    try {
      const pdfDoc = await PDFDocument.create();
      
      // Create default template
      await this.createContractTemplate(pdfDoc, quoteData, contractNumber);

      // Add metadata
      pdfDoc.setTitle(`Contract - ${quoteData.clientName}`);
      pdfDoc.setAuthor('Quote2Contract (Pty) Ltd');
      pdfDoc.setSubject(`Service Contract for ${quoteData.serviceName}`);
      pdfDoc.setCreator('Quote2Contract System');
      pdfDoc.setProducer('Quote2Contract CRM');
      pdfDoc.setCreationDate(new Date());
      pdfDoc.setModificationDate(new Date());

      // Generate unique contract ID
      const contractId = this.generateContractId(contractNumber);
      
      // Save as bytes
      const pdfBytes = await pdfDoc.save();

      return {
        pdfBytes,
        contractId,
        metadata: {
          contractId,
          createdAt: new Date(),
          quoteId: quoteData.id,
          clientName: quoteData.clientName,
          totalAmount: quoteData.total
        }
      };
    } catch (error) {
      console.error('Error generating contract:', error);
      throw error;
    }
  }

  // Create contract template
  private async createContractTemplate(
    pdfDoc: PDFDocument,
    quoteData: QuoteData,
    contractNumber: string
  ) {
    const page = pdfDoc.addPage([595.28, 841.89]); // A4 size
    const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
    const boldFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
    const { width, height } = page.getSize();

    let currentY = height - 60;

    // Header
    page.drawText('QUOTE2CONTRACT SERVICE AGREEMENT', {
      x: 50,
      y: currentY,
      size: 18,
      font: boldFont,
      color: rgb(0, 0.2, 0.4)
    });

    currentY -= 40;

    // Contract Information
    this.drawLabelValue(page, boldFont, font, 'Contract Number:', contractNumber, 50, currentY, 12);
    currentY -= 20;
    
    this.drawLabelValue(page, boldFont, font, 'Date Issued:', new Date().toLocaleDateString('en-ZA'), 50, currentY, 12);
    currentY -= 20;
    
    this.drawLabelValue(page, boldFont, font, 'Quote Reference:', quoteData.quoteNumber, 50, currentY, 12);
    currentY -= 40;

    // Section 1: Parties
    page.drawText('1. THE SERVICE PROVIDER', {
      x: 50,
      y: currentY,
      size: 12,
      font: boldFont,
      color: rgb(0, 0, 0)
    });
    currentY -= 20;

    const providerInfo = [
      'Quote2Contract (Pty) Ltd',
      'Registration No.: [Company Registration Number]',
      'Address: [Company Address]',
      'Contact: support@quote2contract.com'
    ];

    for (const line of providerInfo) {
      page.drawText(line, {
        x: 50,
        y: currentY,
        size: 10,
        font: font,
        color: rgb(0, 0, 0)
      });
      currentY -= 15;
    }

    currentY -= 10;

    // Section 2: The Client
    page.drawText('2. THE CLIENT', {
      x: 50,
      y: currentY,
      size: 12,
      font: boldFont,
      color: rgb(0, 0, 0)
    });
    currentY -= 20;

    const clientInfo = [
      `Full Name: ${quoteData.clientName}`,
      quoteData.clientCompany ? `Company: ${quoteData.clientCompany}` : null,
      `Email: ${quoteData.clientEmail}`,
      quoteData.clientPhone ? `Phone: ${quoteData.clientPhone}` : null,
      quoteData.clientAddress ? `Address: ${quoteData.clientAddress}` : null
    ].filter(Boolean) as string[];

    for (const line of clientInfo) {
      page.drawText(line, {
        x: 50,
        y: currentY,
        size: 10,
        font: font,
        color: rgb(0, 0, 0)
      });
      currentY -= 15;
    }

    currentY -= 10;

    // Section 3: Project Details
    page.drawText('3. PROJECT DETAILS', {
      x: 50,
      y: currentY,
      size: 12,
      font: boldFont,
      color: rgb(0, 0, 0)
    });
    currentY -= 20;

    this.drawLabelValue(page, boldFont, font, 'Service Type:', quoteData.serviceName, 50, currentY, 10);
    currentY -= 20;
    
    if (quoteData.serviceDescription) {
      page.drawText('Description of Work:', {
        x: 50,
        y: currentY,
        size: 10,
        font: boldFont,
        color: rgb(0, 0, 0)
      });
      currentY -= 15;
      
      const description = this.wrapText(quoteData.serviceDescription, 80);
      for (const line of description) {
        if (currentY < 100) {
          const newPage = pdfDoc.addPage([595.28, 841.89]);
          currentY = newPage.getSize().height - 60;
          this.continueOnPage(newPage, font, currentY);
        }
        page.drawText(line, {
          x: 50,
          y: currentY,
          size: 10,
          font: font,
          color: rgb(0, 0, 0)
        });
        currentY -= 15;
      }
    }

    currentY -= 10;

    // Section 4: Quotation & Payment Terms
    if (currentY < 200) {
      const newPage = pdfDoc.addPage([595.28, 841.89]);
      currentY = newPage.getSize().height - 60;
      await this.addPaymentSection(newPage, boldFont, font, quoteData, currentY);
    } else {
      await this.addPaymentSection(page, boldFont, font, quoteData, currentY);
    }
  }

  private async addPaymentSection(
    page: PDFPage,
    boldFont: any,
    font: any,
    quoteData: QuoteData,
    startY: number
  ) {
    let currentY = startY;

    page.drawText('4. QUOTATION & PAYMENT TERMS', {
      x: 50,
      y: currentY,
      size: 12,
      font: boldFont,
      color: rgb(0, 0, 0)
    });
    currentY -= 20;

    this.drawLabelValue(page, boldFont, font, 'Subtotal (Excl. VAT):', `R ${quoteData.subtotal.toFixed(2)}`, 50, currentY, 10);
    currentY -= 15;

    if (quoteData.discounts && quoteData.discounts > 0) {
      this.drawLabelValue(page, boldFont, font, 'Discounts:', `R ${quoteData.discounts.toFixed(2)}`, 50, currentY, 10);
      currentY -= 15;
    }

    if (quoteData.taxes && quoteData.taxes > 0) {
      this.drawLabelValue(page, boldFont, font, 'VAT:', `R ${quoteData.taxes.toFixed(2)}`, 50, currentY, 10);
      currentY -= 15;
    }

    this.drawLabelValue(page, boldFont, font, 'Total Amount:', `R ${quoteData.total.toFixed(2)}`, 50, currentY, 10);
    currentY -= 15;

    this.drawLabelValue(page, boldFont, font, 'Payment Terms:', quoteData.paymentTerms || 'As per quotation', 50, currentY, 10);
    currentY -= 30;

    // Additional Terms
    const terms = [
      '5. PROJECT EXECUTION',
      'Quote2Contract (Pty) Ltd will allocate a verified contractor to perform the work.',
      'The Client agrees to provide access to the site, water, and electricity where reasonably required.',
      '',
      '6. WARRANTY & QUALITY ASSURANCE',
      'All work will be executed according to industry standards and regulations.',
      'Standard workmanship warranty: 12 months, unless otherwise stated.',
      '',
      '7. LIABILITY',
      'Quote2Contract (Pty) Ltd shall not be liable for indirect, incidental, or consequential losses.',
      '',
      '8. GOVERNING LAW',
      'This Agreement shall be governed by the laws of the Republic of South Africa.'
    ];

    for (const term of terms) {
      if (currentY < 60) {
        break;
      }
      
      const fontSize = term.match(/^\d+\./) ? 11 : 9;
      const usedFont = term.match(/^\d+\./) ? boldFont : font;
      
      page.drawText(term, {
        x: 50,
        y: currentY,
        size: fontSize,
        font: usedFont,
        color: rgb(0, 0, 0)
      });
      currentY -= term === '' ? 10 : 15;
    }

    // Signature Areas
    currentY = 150;
    this.addSignatureAreas(page, font, boldFont, currentY);
  }

  private addSignatureAreas(page: PDFPage, font: any, boldFont: any, startY: number) {
    const signatureY = startY;
    
    // Client signature area
    page.drawText('Client Signature:', {
      x: 50,
      y: signatureY,
      size: 11,
      font: boldFont,
      color: rgb(0, 0, 0)
    });
    
    page.drawLine({
      start: { x: 50, y: signatureY - 30 },
      end: { x: 230, y: signatureY - 30 },
      thickness: 1,
      color: rgb(0, 0, 0)
    });

    page.drawText('Date: _________________', {
      x: 50,
      y: signatureY - 50,
      size: 9,
      font: font,
      color: rgb(0, 0, 0)
    });

    // Company signature area
    page.drawText('Company Representative:', {
      x: 320,
      y: signatureY,
      size: 11,
      font: boldFont,
      color: rgb(0, 0, 0)
    });
    
    page.drawLine({
      start: { x: 320, y: signatureY - 30 },
      end: { x: 500, y: signatureY - 30 },
      thickness: 1,
      color: rgb(0, 0, 0)
    });

    page.drawText('Date: _________________', {
      x: 320,
      y: signatureY - 50,
      size: 9,
      font: font,
      color: rgb(0, 0, 0)
    });
  }

  // Add signature to PDF
  async addSignatureToPDF(
    pdfBytes: Uint8Array,
    signatureDataUrl: string,
    signerName: string,
    signerEmail: string,
    signerType: 'CLIENT' | 'COMPANY',
    timestamp: string
  ): Promise<Uint8Array> {
    const pdfDoc = await PDFDocument.load(pdfBytes);
    const pages = pdfDoc.getPages();
    const lastPage = pages[pages.length - 1];
    const font = await pdfDoc.embedFont(StandardFonts.Helvetica);

    // Embed signature image
    const signatureImage = await pdfDoc.embedPng(signatureDataUrl);
    const { width, height } = signatureImage.scale(0.3);
    
    // Position based on signer type
    const position = signerType === 'CLIENT' 
      ? { x: 50, y: 120 }
      : { x: 320, y: 120 };

    // Draw signature
    lastPage.drawImage(signatureImage, {
      x: position.x,
      y: position.y,
      width: width,
      height: height
    });

    // Add signature metadata
    lastPage.drawText(`Signed by: ${signerName}`, {
      x: position.x,
      y: position.y - 15,
      size: 7,
      font: font,
      color: rgb(0.3, 0.3, 0.3)
    });
    
    lastPage.drawText(`Email: ${signerEmail}`, {
      x: position.x,
      y: position.y - 25,
      size: 7,
      font: font,
      color: rgb(0.3, 0.3, 0.3)
    });
    
    lastPage.drawText(`Date: ${timestamp}`, {
      x: position.x,
      y: position.y - 35,
      size: 7,
      font: font,
      color: rgb(0.3, 0.3, 0.3)
    });

    return await pdfDoc.save();
  }

  // Helper methods
  private drawLabelValue(
    page: PDFPage,
    boldFont: any,
    font: any,
    label: string,
    value: string,
    x: number,
    y: number,
    size: number
  ) {
    page.drawText(label, {
      x,
      y,
      size,
      font: boldFont,
      color: rgb(0, 0, 0)
    });
    
    page.drawText(value, {
      x: x + 150,
      y,
      size,
      font: font,
      color: rgb(0.2, 0.2, 0.2)
    });
  }

  private wrapText(text: string, maxChars: number): string[] {
    const words = text.split(' ');
    const lines: string[] = [];
    let currentLine = '';

    for (const word of words) {
      if ((currentLine + word).length <= maxChars) {
        currentLine += (currentLine ? ' ' : '') + word;
      } else {
        if (currentLine) lines.push(currentLine);
        currentLine = word;
      }
    }
    
    if (currentLine) lines.push(currentLine);
    return lines;
  }

  private continueOnPage(page: PDFPage, font: any, y: number) {
    page.drawText('(Continued)', {
      x: 50,
      y,
      size: 9,
      font: font,
      color: rgb(0.5, 0.5, 0.5)
    });
  }

  // Generate unique contract ID
  private generateContractId(contractNumber: string): string {
    const timestamp = Date.now().toString(36);
    const random = crypto.randomBytes(4).toString('hex');
    return `${contractNumber}-${timestamp}-${random}`.toUpperCase();
  }

  // Generate signature hash
  generateSignatureHash(signatureData: any): string {
    return crypto
      .createHash('sha256')
      .update(JSON.stringify(signatureData))
      .digest('hex')
      .substring(0, 32);
  }
}

export const pdfService = new PDFService();
