import { Hono } from 'hono'
import { z } from 'zod'
import {
  InventoryLocationConflictError,
  createInventoryLocation,
  deleteInventoryLocation,
  getInventoryReports,
  listInventoryCountRows,
  listInventoryLocations,
  updateInventoryLocation,
} from '@zync/db/queries'
import type { AppEnv } from '../types'
import { authMiddleware } from '../middleware/auth'
import { requirePermission } from '../middleware/guards'
import { requireModuleEnabled } from '../middleware/require-module-enabled'

export const inventoryRoute = new Hono<AppEnv>()

const inventoryReportsQuerySchema = z.object({
  from: z.string().date(),
  to: z.string().date(),
})

const locationCreateSchema = z.object({
  name: z.string().trim().min(1).max(120),
  code: z.string().trim().max(40).nullable().optional(),
  isDefault: z.boolean().optional(),
  isActive: z.boolean().optional(),
})

const locationPatchSchema = z
  .object({
    name: z.string().trim().min(1).max(120).optional(),
    code: z.string().trim().max(40).nullable().optional(),
    isDefault: z.boolean().optional(),
    isActive: z.boolean().optional(),
  })
  .refine((value) => Object.keys(value).length > 0, {
    message: 'At least one field is required',
  })

inventoryRoute.use('*', authMiddleware)
inventoryRoute.use('*', requireModuleEnabled('invoices'))

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

  const items = await listInventoryCountRows(c.get('db'), session.tid)
  return c.json({ items })
})

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

  const parsed = inventoryReportsQuerySchema.safeParse({
    from: c.req.query('from'),
    to: c.req.query('to'),
  })
  if (!parsed.success) {
    return c.json({ error: 'Invalid query', details: parsed.error.flatten() }, 400)
  }
  if (parsed.data.to < parsed.data.from) {
    return c.json({ error: "'to' must be >= 'from'" }, 400)
  }

  const report = await getInventoryReports(c.get('db'), session.tid, parsed.data)
  return c.json(report)
})

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

  const locations = await listInventoryLocations(c.get('db'), session.tid)
  return c.json({ locations })
})

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

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

  const location = await createInventoryLocation(c.get('db'), session.tid, parsed.data)
  return c.json(location, 201)
})

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

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

  const location = await updateInventoryLocation(c.get('db'), session.tid, c.req.param('id'), parsed.data)
  if (!location) {
    return c.json({ error: 'Not found' }, 404)
  }

  return c.json(location)
})

inventoryRoute.delete('/locations/:id', requirePermission('inventory:manage'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  try {
    const deleted = await deleteInventoryLocation(c.get('db'), session.tid, c.req.param('id'))
    if (!deleted) {
      return c.json({ error: 'Not found' }, 404)
    }

    return c.body(null, 204)
  } catch (error) {
    if (error instanceof InventoryLocationConflictError) {
      return c.json({ error: error.message }, 409)
    }
    throw error
  }
})
