/**
 * Customer CRUD routes — customers module (Task 4).
 * Mounted at /api/customers (behind authMiddleware in routes/customers/router.ts).
 *
 * GET    /             list customers (cursor-paginated, ≤100)
 * POST   /             create customer
 * GET    /:id          get customer with stats
 * PATCH  /:id          update customer
 * DELETE /:id          archive customer (soft delete; 409 if open invoices)
 */
import { Hono } from 'hono'
import { z } from 'zod'
import {
  archiveCustomer,
  createCustomer,
  getCustomerWithStats,
  listCustomers,
  OpenInvoicesError,
  updateCustomer,
} from '@zync/db/queries'
import type { AppEnv } from '../../types'
import { requirePermission } from '../../middleware/guards'
import { createCustomerSchema, updateCustomerSchema } from '../../schemas/customers'
import {
  applyFieldPermissions,
  applyFieldPermissionsToPage,
  attachReadOnlyMeta,
  getFieldPermissionContext,
} from '../field-permissions/enforcement'

export const customersIndexRoute = new Hono<AppEnv>()

const customerIdSchema = z.string().uuid()

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

  const url = new URL(c.req.url)
  const cursor = url.searchParams.get('cursor') ?? undefined
  const limitParam = url.searchParams.get('limit')
  const limit = limitParam ? Math.min(parseInt(limitParam, 10) || 50, 100) : 50
  const status = url.searchParams.get('status') as 'active' | 'archived' | null ?? undefined
  const search = url.searchParams.get('search') ?? undefined

  const db = c.get('db')
  const page = await listCustomers(db, session.tid, { cursor, limit, status, search })
  const { role, rules } = await getFieldPermissionContext(db, session)
  return c.json(applyFieldPermissionsToPage(page, 'customer', role, rules), 200)
})

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

  const parsed = createCustomerSchema.safeParse(await c.req.json())
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }

  const db = c.get('db')
  const customer = await createCustomer(db, session.tid, parsed.data, session.sub)
  return c.json(customer, 201)
})

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

  const customerId = customerIdSchema.safeParse(c.req.param('id'))
  if (!customerId.success) return c.json({ error: 'Invalid customer id' }, 400)

  const db = c.get('db')
  const result = await getCustomerWithStats(db, session.tid, customerId.data)
  if (!result) return c.json({ error: 'Not found' }, 404)
  const { role, rules } = await getFieldPermissionContext(db, session)
  const filtered = applyFieldPermissions(result, 'customer', role, rules)
  return c.json(attachReadOnlyMeta(filtered.data, filtered.readOnly), 200)
})

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

  const customerId = customerIdSchema.safeParse(c.req.param('id'))
  if (!customerId.success) return c.json({ error: 'Invalid customer id' }, 400)

  const parsed = updateCustomerSchema.safeParse(await c.req.json())
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }

  const db = c.get('db')
  try {
    const customer = await updateCustomer(db, session.tid, customerId.data, parsed.data, session.sub)
    return c.json(customer, 200)
  } catch (err) {
    if (err instanceof Error && err.message === 'Customer not found') {
      return c.json({ error: 'Not found' }, 404)
    }
    throw err
  }
})

// DELETE /api/customers/:id (soft archive)
customersIndexRoute.delete('/:id', requirePermission('customers:delete'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const customerId = customerIdSchema.safeParse(c.req.param('id'))
  if (!customerId.success) return c.json({ error: 'Invalid customer id' }, 400)

  const db = c.get('db')
  try {
    const customer = await archiveCustomer(db, session.tid, customerId.data, session.sub)
    return c.json(customer, 200)
  } catch (err) {
    if (err instanceof OpenInvoicesError) {
      return c.json({ error: 'open_invoices' }, 409)
    }
    if (err instanceof Error && err.message === 'Customer not found') {
      return c.json({ error: 'Not found' }, 404)
    }
    throw err
  }
})
