from pathlib import Path

root = Path.cwd()
controller = root / 'src/modules/customers/customers.controller.ts'
service = root / 'src/modules/customers/customers.service.ts'

if not controller.exists() or not service.exists():
    raise SystemExit('Run this script from backend root: ~/rc.clientspaymenetgetway.com/backend')

c = controller.read_text()
if "uploadCustomerDocument(" not in c:
    marker = "  @Get(':id')\n  findOne"
    block = """  @Post(':id/documents')
  uploadCustomerDocument(
    @Param('id') id: string,
    @Body() body: any,
    @CurrentUser() user: AuthUser,
  ) {
    return this.customersService.uploadCustomerDocument(
      Number(id),
      body,
      user,
    );
  }

"""
    if marker not in c:
        raise SystemExit('Cannot find insertion point in customers.controller.ts')
    c = c.replace(marker, block + marker, 1)
    controller.write_text(c)
    print('Patched customers.controller.ts')
else:
    print('customers.controller.ts already patched')

s = service.read_text()
if "DocumentStatus" not in s:
    s = s.replace("import { DocumentEntity } from '../documents/entities/document.entity';", "import { DocumentEntity, DocumentStatus, DocumentType } from '../documents/entities/document.entity';")
elif "DocumentType" not in s:
    s = s.replace("import { DocumentEntity, DocumentStatus } from '../documents/entities/document.entity';", "import { DocumentEntity, DocumentStatus, DocumentType } from '../documents/entities/document.entity';")

if "async uploadCustomerDocument(" not in s:
    marker = "  async findDocuments(id: number, currentUser: AuthUser) {"
    block = r'''  private normalizeCustomerDocumentKind(value?: string) {
    const raw = String(value || 'other').trim().toLowerCase();
    if (['cin', 'cni', 'id', 'identity', 'identite', 'carte_identite'].includes(raw)) return 'cin';
    if (['passport', 'passeport'].includes(raw)) return 'passport';
    if (['license', 'licence', 'permis', 'driver_license', 'driving_license'].includes(raw)) return 'license';
    if (['address', 'justificatif', 'proof_address'].includes(raw)) return 'address';
    return raw || 'other';
  }

  private customerDocumentLabel(kind: string) {
    switch (kind) {
      case 'cin': return 'CIN';
      case 'passport': return 'Passeport';
      case 'license': return 'Permis';
      case 'address': return 'Justificatif adresse';
      default: return 'Document client';
    }
  }

  private extractBase64File(body: any) {
    const raw = body?.fileBase64 || body?.imageBase64 || body?.base64 || body?.dataUrl;
    if (!raw || typeof raw !== 'string') return null;
    const match = raw.match(/^data:([^;]+);base64,(.+)$/);
    if (match) return { mime: match[1], base64: match[2] };
    return { mime: body?.mimeType || 'application/octet-stream', base64: raw };
  }

  private extensionFromMime(mime?: string, fileName?: string) {
    const fromName = String(fileName || '').split('.').pop();
    if (fromName && fromName.length <= 8 && fromName !== fileName) return fromName.toLowerCase();
    if (mime?.includes('pdf')) return 'pdf';
    if (mime?.includes('png')) return 'png';
    if (mime?.includes('webp')) return 'webp';
    if (mime?.includes('jpeg') || mime?.includes('jpg')) return 'jpg';
    return 'bin';
  }

  async uploadCustomerDocument(id: number, body: any, currentUser: AuthUser) {
    const customer = await this.findOneForUser(id, currentUser);
    const kind = this.normalizeCustomerDocumentKind(body?.documentType || body?.type || body?.kind);
    const label = this.customerDocumentLabel(kind);
    const uploaded = this.extractBase64File(body);
    const originalName = body?.fileName || body?.originalName || `${label}.pdf`;

    let fileUrl = body?.fileUrl || body?.url || null;
    let filePath = body?.filePath || null;
    let fileName = originalName;

    if (uploaded) {
      const fs = await import('fs');
      const path = await import('path');
      const ext = this.extensionFromMime(uploaded.mime, originalName);
      const safeKind = kind.replace(/[^a-z0-9_-]/gi, '_').toLowerCase();
      fileName = `${safeKind}-${Date.now()}.${ext}`;
      const dir = path.join(process.cwd(), 'storage', 'documents', 'customers', String(customer.id));
      fs.mkdirSync(dir, { recursive: true });
      filePath = path.join(dir, fileName);
      fs.writeFileSync(filePath, Buffer.from(uploaded.base64, 'base64'));
      fileUrl = `/storage/documents/customers/${customer.id}/${fileName}`;
    }

    if (!fileUrl) {
      throw new BadRequestException('Fichier document client manquant');
    }

    const token = `${Date.now().toString(16)}${Math.random().toString(16).slice(2, 12)}`;
    const documentNumber = `CUSTOMER-${label.toUpperCase().replace(/\s+/g, '-')}-${new Date().getFullYear()}-${String(Date.now()).slice(-6)}`;

    const doc = this.documentRepository.create({
      type: DocumentType.OCR_CLIENT_DOCUMENT,
      status: DocumentStatus.GENERATED,
      documentNumber,
      verifyToken: token,
      verifyUrl: `/verify/document/${token}`,
      agencyId: customer.agency?.id || currentUser.agencyId || undefined,
      customerId: customer.id,
      title: body?.title || `Copie ${label} — ${customer.fullName || customer.email || customer.id}`,
      fileName,
      filePath,
      fileUrl,
      metadata: {
        ...(body?.metadata || {}),
        source: 'customer_upload',
        documentKind: kind,
        documentLabel: label,
        originalName,
        mimeType: uploaded?.mime || body?.mimeType || null,
        uploadedAt: new Date().toISOString(),
      },
    });

    const saved = await this.documentRepository.save(doc);
    return saved;
  }

'''
    if marker not in s:
        raise SystemExit('Cannot find insertion point in customers.service.ts')
    s = s.replace(marker, block + marker, 1)
    service.write_text(s)
    print('Patched customers.service.ts')
else:
    print('customers.service.ts already patched')
