import { Hono } from 'hono'
import type { AppEnv } from '../../types'
import { authMiddleware } from '../../middleware/auth'
import { requireModuleEnabled } from '../../middleware/require-module-enabled'
import { requirePermission } from '../../middleware/guards'
import {
  approveTimeEntry,
  approveTimeEntrySchema,
  bulkReviewTimeEntries,
  bulkReviewTimeEntriesSchema,
  createDb,
  exportApprovedTimeEntries,
  exportApprovedTimeEntriesSchema,
  listTimeApprovalEntries,
  listTimeApprovalEntriesSchema,
  rejectTimeEntry,
  rejectTimeEntrySchema,
  resubmitTimeEntry,
} from '@zync/db/queries'

type TimeApprovalErrorStatus = 400 | 401 | 403 | 404 | 409 | 422 | 500

function normalizeErrorStatus(error: unknown): TimeApprovalErrorStatus {
  const status = error instanceof Error && 'status' in error ? Number((error as { status?: number }).status) : 500
  switch (status) {
    case 400:
    case 401:
    case 403:
    case 404:
    case 409:
    case 422:
      return status
    default:
      return 500
  }
}

export const timeApprovalRoutes = new Hono<AppEnv>()

timeApprovalRoutes.use('*', authMiddleware)
timeApprovalRoutes.use('*', requireModuleEnabled('time_management'))

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

    const parsed = listTimeApprovalEntriesSchema.safeParse(
      Object.fromEntries(new URL(c.req.url).searchParams),
    )
    if (!parsed.success) return c.json({ error: 'Invalid query', issues: parsed.error.issues }, 400)

    const items = await listTimeApprovalEntries(createDb(c.env), session.tid, parsed.data)
    return c.json(items)
  },
)

timeApprovalRoutes.post(
  '/approvals/bulk',
  requirePermission('time:manage'),
  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 = bulkReviewTimeEntriesSchema.safeParse(body)
    if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)

    const result = await bulkReviewTimeEntries(createDb(c.env), session.tid, session.sub, parsed.data)
    return c.json(result)
  },
)

timeApprovalRoutes.post(
  '/:id/approve',
  requirePermission('time:manage'),
  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(() => ({}))
    const parsed = approveTimeEntrySchema.safeParse(body)
    if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)

    try {
      const result = await approveTimeEntry(createDb(c.env), session.tid, session.sub, c.req.param('id'), parsed.data.note)
      return c.json(result)
    } catch (error) {
      c.status(normalizeErrorStatus(error))
      return c.json({ error: error instanceof Error ? error.message : 'Internal error' })
    }
  },
)

timeApprovalRoutes.post(
  '/:id/reject',
  requirePermission('time:manage'),
  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 = rejectTimeEntrySchema.safeParse(body)
    if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)

    try {
      const result = await rejectTimeEntry(createDb(c.env), session.tid, session.sub, c.req.param('id'), parsed.data.note)
      return c.json(result)
    } catch (error) {
      c.status(normalizeErrorStatus(error))
      return c.json({ error: error instanceof Error ? error.message : 'Internal error' })
    }
  },
)

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

    try {
      const result = await resubmitTimeEntry(createDb(c.env), session.tid, session.sub, c.req.param('id'))
      return c.json(result)
    } catch (error) {
      c.status(normalizeErrorStatus(error))
      return c.json({ error: error instanceof Error ? error.message : 'Internal error' })
    }
  },
)

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

    const parsed = exportApprovedTimeEntriesSchema.safeParse(
      Object.fromEntries(new URL(c.req.url).searchParams),
    )
    if (!parsed.success) return c.json({ error: 'Invalid query', issues: parsed.error.issues }, 400)

    try {
      const result = await exportApprovedTimeEntries(createDb(c.env), session.tid, session.sub, parsed.data)
      return new Response(result.csv, {
        headers: {
          'Content-Type': 'text/csv; charset=utf-8',
          'Content-Disposition': `attachment; filename="${result.filename}"`,
        },
      })
    } catch (error) {
      c.status(normalizeErrorStatus(error))
      return c.json({ error: error instanceof Error ? error.message : 'Internal error' })
    }
  },
)
