/**
 * Proposals routes — marketing-catalogs-campaigns (wave-9 leaf 3).
 * Mounted at /api/marketing/proposals (behind authMiddleware in router.ts).
 *
 * GET    /                        list proposals (paginated, filterable) — wave-13 extended
 * POST   /                        create proposal
 * GET    /:id                     get proposal detail
 * PATCH  /:id                     update proposal
 * DELETE /:id                     delete proposal
 * POST   /:id/send                mark proposal as sent
 * POST   /:id/accept              mark proposal as accepted
 * POST   /:id/reject              mark proposal as rejected
 * POST   /:id/create-contract     create contract from accepted proposal (wave-10 leaf6)
 */
import { Hono } from 'hono'
import { z } from 'zod'
import type { AppEnv } from '../../types'
import { requirePermission } from '../../middleware/guards'
import {
  listProposalsPaginated,
  getProposal,
  createProposal,
  updateProposal,
  deleteProposal,
  sendProposal,
  acceptProposal,
  rejectProposal,
  createProposalSchema,
  updateProposalSchema,
  createContractFromProposal,
  assertTenantOwnsCustomer,
  assertTenantOwnsLead,
  invalidTenantReferenceBody,
} from '@zync/db/queries'

export const proposalsRoute = new Hono<AppEnv>()

// ── wave-13: extended list query schema ───────────────────────────────────────

const PROPOSAL_STATUSES = ['DRAFT', 'SENT', 'VIEWED', 'ACCEPTED', 'REJECTED', 'EXPIRED'] as const
const SORT_OPTIONS = ['title', '-title', 'customer_name', '-customer_name', 'total_value', '-total_value', 'status', '-status', 'expires_at', '-expires_at', 'sent_at', '-sent_at', 'created_at', '-created_at'] as const

const proposalListQuerySchema = z.object({
  status: z.enum(PROPOSAL_STATUSES).optional(),
  customer_id: z.string().uuid().optional(),
  expires_before: z.string().datetime({ offset: true }).optional(),
  expires_after: z.string().datetime({ offset: true }).optional(),
  created_after: z.string().datetime({ offset: true }).optional(),
  created_before: z.string().datetime({ offset: true }).optional(),
  sort: z.enum(SORT_OPTIONS).optional(),
  page: z.coerce.number().int().min(1).optional(),
  per_page: z.coerce.number().int().min(1).max(100).optional(),
})

// GET /api/marketing/proposals
proposalsRoute.get('/', requirePermission('marketing:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')

  const raw = {
    status: c.req.query('status'),
    customer_id: c.req.query('customer_id'),
    expires_before: c.req.query('expires_before'),
    expires_after: c.req.query('expires_after'),
    created_after: c.req.query('created_after'),
    created_before: c.req.query('created_before'),
    sort: c.req.query('sort'),
    page: c.req.query('page'),
    per_page: c.req.query('per_page'),
  }

  const parsed = proposalListQuerySchema.safeParse(raw)
  if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)

  const q = parsed.data

  const result = await listProposalsPaginated(db, session.tid, {
    status: q.status?.toLowerCase(),
    customer_id: q.customer_id,
    expires_before: q.expires_before,
    expires_after: q.expires_after,
    created_after: q.created_after,
    created_before: q.created_before,
    sort: q.sort,
    page: q.page,
    per_page: q.per_page,
  })

  return c.json(result)
})

// POST /api/marketing/proposals
proposalsRoute.post('/', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')

  const body = await c.req.json().catch(() => null)
  const parsed = createProposalSchema.safeParse(body)
  if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)

  if (!(await assertTenantOwnsCustomer(db, session.tid, parsed.data.customerId ?? null))) {
    return c.json(invalidTenantReferenceBody('customerId'), 400)
  }
  if (!(await assertTenantOwnsLead(db, session.tid, parsed.data.leadId ?? null))) {
    return c.json(invalidTenantReferenceBody('leadId'), 400)
  }

  const proposal = await createProposal(db, session.tid, parsed.data)
  return c.json({ proposal }, 201)
})

// GET /api/marketing/proposals/:id
proposalsRoute.get('/:id', requirePermission('marketing:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  const proposal = await getProposal(db, session.tid, id)
  if (!proposal) return c.json({ error: 'Proposal not found' }, 404)
  return c.json({ proposal })
})

// PATCH /api/marketing/proposals/:id
proposalsRoute.patch('/:id', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  const body = await c.req.json().catch(() => null)
  const parsed = updateProposalSchema.safeParse(body)
  if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)

  if (parsed.data.customerId !== undefined) {
    if (!(await assertTenantOwnsCustomer(db, session.tid, parsed.data.customerId))) {
      return c.json(invalidTenantReferenceBody('customerId'), 400)
    }
  }
  if (parsed.data.leadId !== undefined) {
    if (!(await assertTenantOwnsLead(db, session.tid, parsed.data.leadId))) {
      return c.json(invalidTenantReferenceBody('leadId'), 400)
    }
  }

  try {
    const proposal = await updateProposal(db, session.tid, id, parsed.data)
    return c.json({ proposal })
  } catch {
    return c.json({ error: 'Proposal not found' }, 404)
  }
})

// DELETE /api/marketing/proposals/:id
proposalsRoute.delete('/:id', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  await deleteProposal(db, session.tid, id)
  return c.json({ ok: true })
})

// POST /api/marketing/proposals/:id/send
proposalsRoute.post('/:id/send', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  try {
    const proposal = await sendProposal(db, session.tid, id)
    return c.json({ proposal })
  } catch {
    return c.json({ error: 'Proposal not found' }, 404)
  }
})

// POST /api/marketing/proposals/:id/accept
proposalsRoute.post('/:id/accept', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  try {
    const proposal = await acceptProposal(db, session.tid, id)
    return c.json({ proposal })
  } catch {
    return c.json({ error: 'Proposal not found' }, 404)
  }
})

// POST /api/marketing/proposals/:id/reject
proposalsRoute.post('/:id/reject', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  try {
    const proposal = await rejectProposal(db, session.tid, id)
    return c.json({ proposal })
  } catch {
    return c.json({ error: 'Proposal not found' }, 404)
  }
})

// ── Proposal-to-Contract flow (wave-10 leaf 6) ───────────────────────────────

// POST /api/marketing/proposals/:id/create-contract
proposalsRoute.post('/:id/create-contract', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  try {
    const result = await createContractFromProposal(db, session.tid, session.sub, id)
    return c.json(result, 201)
  } catch (err) {
    if (err instanceof Error) {
      if (err.message === 'Proposal not found') return c.json({ error: 'Proposal not found' }, 404)
      if (err.message.includes('must be accepted')) return c.json({ error: err.message }, 422)
      if (err.message.includes('already created')) return c.json({ error: err.message }, 409)
    }
    throw err
  }
})
