/**
 * Proposal-to-Contract conversion — proposal-to-contract (wave-10 leaf 6).
 *
 * createContractFromProposal:
 *   1. Reads accepted proposal (status must be 'accepted').
 *   2. Creates draft contract pre-filled from proposal data.
 *   3. Links proposals.contractId = contract.id (bidirectional).
 *   4. Writes audit log.
 *
 * Routes import via @zync/db/queries barrel.
 */
import { and, eq } from 'drizzle-orm'
import type { Db } from '../client'
import { proposals } from '../schema/proposals'
import { contracts } from '../schema/contracts'
import { auditLog } from './_audit-forward'
import type { ProposalLineItem } from './proposals'
import type { Contract } from './contracts'

export interface CreateContractFromProposalResult {
  contract: Contract
}

export async function createContractFromProposal(
  db: Db,
  tenantId: string,
  userId: string,
  proposalId: string,
): Promise<CreateContractFromProposalResult> {
  return db.transaction(async (tx) => {
    // 1. Read accepted proposal
    const [proposal] = await tx
      .select()
      .from(proposals)
      .where(and(eq(proposals.tenantId, tenantId), eq(proposals.id, proposalId)))
      .limit(1)

    if (!proposal) throw new Error('Proposal not found')
    if (proposal.status !== 'accepted') {
      throw new Error(`Proposal must be accepted to create a contract (current status: ${proposal.status})`)
    }
    if (proposal.contractId) {
      throw new Error('Contract already created for this proposal')
    }

    // 2. Build contract content from proposal line items
    const lineItems = (proposal.lineItems as ProposalLineItem[]) ?? []
    let content = `## Scope of Work\n\nThis contract is based on proposal: ${proposal.title}\n\n`

    if (lineItems.length > 0) {
      content += '### Line Items\n\n'
      for (const item of lineItems) {
        content += `- **${item.name}** — Qty: ${item.qty} × ${item.unitPrice} = ${item.total}\n`
      }
      if (proposal.subtotal) content += `\n**Subtotal:** ${proposal.subtotal}\n`
      if (proposal.discount) content += `**Discount:** ${proposal.discount}\n`
      if (proposal.total) content += `**Total:** ${proposal.total}\n`
    }

    if (proposal.notes) {
      content += `\n### Notes\n\n${proposal.notes}\n`
    }

    // 3. Create draft contract
    const now = new Date()
    const [contract] = await tx
      .insert(contracts)
      .values({
        tenantId,
        customerId: proposal.customerId ?? null,
        title: `Contract for: ${proposal.title}`,
        content,
        status: 'draft',
        createdAt: now,
        updatedAt: now,
      })
      .returning()

    if (!contract) throw new Error('Failed to create contract')

    // 4. Link proposal → contract
    await tx
      .update(proposals)
      .set({ contractId: contract.id, updatedAt: now })
      .where(and(eq(proposals.tenantId, tenantId), eq(proposals.id, proposalId)))

    // 5. Audit log — contract created
    await tx.insert(auditLog).values({
      tenantId,
      actorId: userId,
      actorType: 'user',
      entityType: 'contract',
      entityId: contract.id,
      action: 'contract.created_from_proposal',
      changes: { proposalId: [null, proposalId] },
    })

    // 6. Audit log — proposal updated
    await tx.insert(auditLog).values({
      tenantId,
      actorId: userId,
      actorType: 'user',
      entityType: 'proposal',
      entityId: proposalId,
      action: 'proposal.contract_linked',
      changes: { contractId: [null, contract.id] },
    })

    // Serialize contract
    const serializedContract: Contract = {
      id: contract.id,
      tenantId: contract.tenantId,
      customerId: contract.customerId ?? null,
      title: contract.title,
      content: contract.content,
      status: contract.status as Contract['status'],
      signerEmail: contract.signerEmail ?? null,
      signerName: contract.signerName ?? null,
      sentAt: contract.sentAt ? contract.sentAt.toISOString() : null,
      signedAt: contract.signedAt ? contract.signedAt.toISOString() : null,
      voidedAt: contract.voidedAt ? contract.voidedAt.toISOString() : null,
      signatureData: contract.signatureData ?? null,
      metadata: contract.metadata ?? {},
      createdAt: contract.createdAt.toISOString(),
      updatedAt: contract.updatedAt.toISOString(),
    }

    return { contract: serializedContract }
  })
}
