/**
 * /v1/customers routes — tenant-public-api (wave-11 leaf-D).
 *
 * GET  /v1/customers        — list (paginated, filterable)
 * GET  /v1/customers/:id    — get single
 * POST /v1/customers        — create
 * PATCH /v1/customers/:id   — update
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { listCustomers, createCustomer, updateCustomer, getCustomerWithStats } from '@zync/db/queries'
import {
  hasScope,
  serializeCustomer,
  errForbiddenScope,
  errNotFound,
  errValidation,
} from '@zync/public-api'
import type { ApiKeyContext } from '../middleware/auth'
import type { Env } from '../env'
import { createDb } from '../db'

type AppEnv = { Bindings: Env }

export const customersRouter = new Hono<AppEnv>()

const listQuerySchema = z.object({
  limit: z.coerce.number().int().min(1).max(100).default(20),
  cursor: z.string().optional(),
  status: z.enum(['active', 'archived']).optional(),
  search: z.string().optional(),
})

const createBodySchema = z.object({
  name: z.string().min(1),
  company: z.string().optional(),
  email: z.string().email().optional(),
  phone: z.string().optional(),
  address: z.object({
    street: z.string().optional(),
    city: z.string().optional(),
    state: z.string().optional(),
    zip: z.string().optional(),
    country: z.string().optional(),
  }).optional(),
  notes: z.string().optional(),
})

const updateBodySchema = createBodySchema.partial()

customersRouter.get('/', async (c) => {
  const apiKey = c.get('apiKey' as never) as ApiKeyContext
  if (!hasScope(apiKey.scopes, 'customers:read')) {
    return errForbiddenScope('customers:read')
  }

  const parsed = listQuerySchema.safeParse(Object.fromEntries(new URL(c.req.url).searchParams))
  if (!parsed.success) {
    return errValidation('Invalid query parameters')
  }

  const db = createDb(c.env)
  const page = await listCustomers(db, apiKey.tenantId, {
    cursor: parsed.data.cursor,
    limit: parsed.data.limit,
    status: parsed.data.status,
    search: parsed.data.search,
  })

  return c.json({
    data: page.items.map((row) => serializeCustomer(row)),
    meta: {
      total: page.total,
      next_cursor: page.nextCursor,
      has_more: page.nextCursor !== null,
      limit: parsed.data.limit,
    },
  })
})

customersRouter.get('/:id', async (c) => {
  const apiKey = c.get('apiKey' as never) as ApiKeyContext
  if (!hasScope(apiKey.scopes, 'customers:read')) {
    return errForbiddenScope('customers:read')
  }

  const db = createDb(c.env)
  const customer = await getCustomerWithStats(db, apiKey.tenantId, c.req.param('id'))

  if (!customer) return errNotFound('Customer')

  return c.json({
    data: serializeCustomer(customer.customer),
  })
})

customersRouter.post('/', async (c) => {
  const apiKey = c.get('apiKey' as never) as ApiKeyContext
  if (!hasScope(apiKey.scopes, 'customers:write')) {
    return errForbiddenScope('customers:write')
  }

  const body = await c.req.json().catch(() => null)
  const parsed = createBodySchema.safeParse(body)
  if (!parsed.success) {
    return errValidation(parsed.error.issues[0]?.message ?? 'Invalid body', parsed.error.issues[0]?.path[0] as string)
  }

  const db = createDb(c.env)
  const customer = await createCustomer(db, apiKey.tenantId, {
    name: parsed.data.name,
    company: parsed.data.company ?? null,
    email: parsed.data.email ?? null,
    phone: parsed.data.phone ?? null,
    address: parsed.data.address ?? null,
    notes: parsed.data.notes ?? null,
  })

  return c.json({
    data: serializeCustomer(customer),
  }, 201)
})

customersRouter.patch('/:id', async (c) => {
  const apiKey = c.get('apiKey' as never) as ApiKeyContext
  if (!hasScope(apiKey.scopes, 'customers:write')) {
    return errForbiddenScope('customers:write')
  }

  const body = await c.req.json().catch(() => null)
  const parsed = updateBodySchema.safeParse(body)
  if (!parsed.success) {
    return errValidation(parsed.error.issues[0]?.message ?? 'Invalid body', parsed.error.issues[0]?.path[0] as string)
  }

  const db = createDb(c.env)
  try {
    const customer = await updateCustomer(db, apiKey.tenantId, c.req.param('id'), {
      name: parsed.data.name,
      company: parsed.data.company,
      email: parsed.data.email,
      phone: parsed.data.phone,
      address: parsed.data.address,
      notes: parsed.data.notes,
    })

    return c.json({
      data: serializeCustomer(customer),
    })
  } catch {
    return errNotFound('Customer')
  }
})
