/**
 * Vendor CRUD routes — vendors-suppliers (wave-11 leaf-E).
 * Mounted at /api/vendors.
 *
 * GET    /           → PaginatedResponse<VendorListItem> (expenses:read)
 * POST   /           → Vendor (expenses:write)
 * GET    /suggest    → VendorSuggestion[] (expenses:write)
 * GET    /:id        → VendorWithStats (expenses:read)
 * PATCH  /:id        → Vendor (expenses:write)
 * POST   /:id/archive→ Vendor (expenses:write)
 */
import { Hono } from 'hono'
import { z } from 'zod'
import type { AppEnv } from '../types'
import { authMiddleware } from '../middleware/auth'
import { requirePermission } from '../middleware/guards'
import {
  listVendors,
  getVendor,
  createVendor,
  updateVendor,
  archiveVendor,
  suggestVendors,
} from '@zync/db/queries'

// ── Validation schemas ─────────────────────────────────────────────────────────

const createVendorSchema = z
  .object({
    name: z.string().min(1).max(200),
    taxId: z.string().max(20).optional(),
    withholdingRate: z.number().min(0).max(1).nullable().optional(),
    withholdingCertNumber: z.string().max(60).optional(),
    withholdingCertExpiry: z.string().date().optional(),
    defaultCategory: z.string().max(40).optional(),
    defaultVatDeductible: z.boolean().optional(),
    paymentTermsDays: z.number().int().min(0).max(365).optional(),
    email: z.string().email().max(254).optional(),
    phone: z.string().max(40).optional(),
    address: z.string().max(500).optional(),
    notes: z.string().max(2000).optional(),
  })
  .strict()

const updateVendorSchema = createVendorSchema.partial()

export const vendorRoutes = new Hono<AppEnv>()

vendorRoutes.use('*', authMiddleware)

// ── GET /api/vendors/suggest ──────────────────────────────────────────────────
// Must be before /:id to avoid conflict

vendorRoutes.get('/suggest', requirePermission('expenses:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const q = c.req.query('q') ?? ''
  if (!q.trim()) {
    return c.json([], 200)
  }

  const db = c.get('db')
  const suggestions = await suggestVendors(db, session.tid, q, 10)
  return c.json(suggestions, 200)
})

// ── GET /api/vendors ──────────────────────────────────────────────────────────

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

  const q = c.req.query('q') ?? undefined
  const archived = c.req.query('archived') === 'true'
  const limitRaw = parseInt(c.req.query('limit') ?? '50', 10)
  const limit = isNaN(limitRaw) || limitRaw < 1 ? 50 : Math.min(limitRaw, 200)

  const db = c.get('db')
  const result = await listVendors({ tenantId: session.tid, q, archived, limit, db })
  return c.json(result, 200)
})

// ── POST /api/vendors ─────────────────────────────────────────────────────────

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

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

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

// ── GET /api/vendors/:id ──────────────────────────────────────────────────────

vendorRoutes.get('/:id', requirePermission('expenses: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 vendor = await getVendor(db, session.tid, c.req.param('id'))
  if (!vendor) {
    return c.json({ error: 'Vendor not found' }, 404)
  }
  return c.json(vendor, 200)
})

// ── PATCH /api/vendors/:id ────────────────────────────────────────────────────

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

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

  const db = c.get('db')
  const vendor = await updateVendor(db, session.tid, session.sub, c.req.param('id'), parsed.data)
  if (!vendor) {
    return c.json({ error: 'Vendor not found' }, 404)
  }
  return c.json(vendor, 200)
})

// ── POST /api/vendors/:id/archive ─────────────────────────────────────────────

vendorRoutes.post('/:id/archive', requirePermission('expenses: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 vendor = await archiveVendor(db, session.tid, session.sub, c.req.param('id'))
  if (!vendor) {
    return c.json({ error: 'Vendor not found' }, 404)
  }
  return c.json(vendor, 200)
})
