/**
 * Lead-to-Proposal flow — lead-to-proposal-flow (wave-10 leaf 6).
 *
 * createProposalFromLead:
 *   1. Reads the lead (verifies it exists under tenantId).
 *   2. Creates a draft proposal pre-filled with lead data.
 *   3. Links proposal.leadId = leadId.
 *   4. Writes audit log.
 *
 * Routes import via @zync/db/queries barrel.
 */
import { and, desc, eq } from 'drizzle-orm'
import { generateProposalPublicToken } from '@zync/types'
import type { Db } from '../client'
import { leadActivities, leads } from '../schema/marketing'
import { proposals } from '../schema/proposals'
import { auditLog } from './_audit-forward'
import type { ProposalObject } from './proposals'
import { serializeProposalRow } from './proposals'
import type { ProposalContent } from '@zync/types'

function escapeHtml(value: string): string {
  return value
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#39;')
}

function truncateNote(value: string | null | undefined): string | null {
  const trimmed = value?.trim()
  if (!trimmed) return null
  return trimmed.slice(0, 200)
}

export function buildLeadProposalDraft(args: {
  company: string | null
  leadName: string
  notePreview: string | null
  estimatedValue: string | null
}): {
  subject: string
  content: ProposalContent
  totalAmount: string
  notes: string | null
} {
  const companyOrName = args.company?.trim() || args.leadName.trim()
  const introHtml = args.notePreview
    ? `<p>${escapeHtml(args.notePreview)}</p>`
    : `<p>Proposal prepared for ${escapeHtml(companyOrName)}.</p>`

  return {
    subject: `Proposal for ${companyOrName}`,
    content: {
      sections: [
        {
          type: 'text',
          id: crypto.randomUUID(),
          html: introHtml,
        },
        {
          type: 'line_items',
          id: crypto.randomUUID(),
          items: [],
        },
      ],
      settings: {
        show_line_tax: true,
        show_subtotal: true,
        discount_pct: 0,
        currency: 'USD',
      },
    },
    totalAmount: args.estimatedValue ?? '0',
    notes: args.notePreview,
  }
}

export type CreateProposalFromLeadResult = ProposalObject

export async function createProposalFromLead(
  db: Db,
  tenantId: string,
  userId: string,
  leadId: string,
): Promise<CreateProposalFromLeadResult> {
  return db.transaction(async (tx) => {
    // 1. Verify lead exists and belongs to tenant
    const [lead] = await tx
      .select()
      .from(leads)
      .where(and(eq(leads.tenantId, tenantId), eq(leads.id, leadId)))
      .limit(1)

    if (!lead) throw new Error('Lead not found')

    const [mostRecentNote] = await tx
      .select({ content: leadActivities.content })
      .from(leadActivities)
      .where(and(eq(leadActivities.tenantId, tenantId), eq(leadActivities.leadId, leadId), eq(leadActivities.type, 'note')))
      .orderBy(desc(leadActivities.createdAt))
      .limit(1)

    const draft = buildLeadProposalDraft({
      company: lead.company ?? null,
      leadName: lead.name,
      notePreview: truncateNote(mostRecentNote?.content),
      estimatedValue: lead.estimatedValue ?? null,
    })

    // 3. Create draft proposal linked to the lead
    const [proposal] = await tx
      .insert(proposals)
      .values({
        tenantId,
        leadId: lead.id,
        customerId: lead.customerId ?? null,
        title: draft.subject,
        name: draft.subject,
        status: 'draft',
        content: draft.content,
        lineItems: [],
        subtotal: lead.estimatedValue ?? null,
        discount: null,
        total: lead.estimatedValue ?? null,
        totalAmount: draft.totalAmount,
        notes: draft.notes,
        validUntil: null,
        expiresAt: null,
        sentAt: null,
        publicToken: generateProposalPublicToken(),
        createdBy: userId,
      })
      .returning()

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

    await tx.insert(leadActivities).values({
      tenantId,
      leadId: lead.id,
      userId,
      type: 'note',
      content: 'Proposal created',
      metadata: { proposalId: proposal.id },
    })

    // 4. Audit log
    await tx.insert(auditLog).values({
      tenantId,
      actorId: userId,
      actorType: 'user',
      entityType: 'proposal',
      entityId: proposal.id,
      action: 'proposal.created_from_lead',
      changes: { leadId: [null, leadId] },
    })

    return serializeProposalRow(proposal)
  })
}
