import { Hono } from 'hono'
import { z } from 'zod'
import { TenantTier } from '@zync/types'
import {
  dismissSuggestion,
  listMergeSuggestions,
  mergeCustomers,
  MergeNotFoundError,
  AlreadyMergedError,
  scanForDuplicates,
} from '@zync/db/queries'
import { requirePermission, requireTier } from '../../middleware/guards'
import type { AppEnv } from '../../types'

const suggestionIdSchema = z.object({
  id: z.string().uuid(),
})

const listQuerySchema = z.object({
  limit: z.coerce.number().int().min(1).max(100).optional().default(50),
})

const mergeBodySchema = z.object({
  keepId: z.string().uuid(),
  deleteId: z.string().uuid(),
})

export const customerDedupRoutes = new Hono<AppEnv>()

customerDedupRoutes.use('/duplicates', requireTier(TenantTier.BUSINESS))
customerDedupRoutes.use('/duplicates/*', requireTier(TenantTier.BUSINESS))
customerDedupRoutes.use('/merge', requireTier(TenantTier.BUSINESS))
customerDedupRoutes.use('/merge/*', requireTier(TenantTier.BUSINESS))

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

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

  const result = await listMergeSuggestions(c.get('db'), session.tid, { limit: parsed.data.limit })
  return c.json(result)
})

customerDedupRoutes.post('/duplicates/:id/dismiss', 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 = suggestionIdSchema.safeParse(c.req.param())
  if (!parsed.success) {
    return c.json({ error: 'Invalid suggestion id', issues: parsed.error.issues }, 400)
  }

  await dismissSuggestion(c.get('db'), session.tid, parsed.data.id, session.sub)
  return c.body(null, 204)
})

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

  const parsed = mergeBodySchema.safeParse(await c.req.json().catch(() => null))
  if (!parsed.success) {
    return c.json({ error: 'Validation error', issues: parsed.error.issues }, 400)
  }
  if (parsed.data.keepId === parsed.data.deleteId) {
    return c.json({ error: 'keepId and deleteId must differ' }, 400)
  }

  try {
    const result = await mergeCustomers(
      c.get('db'),
      session.tid,
      {
        userId: session.sub,
        name: null,
        email: null,
      },
      parsed.data,
    )
    return c.json(result)
  } catch (error) {
    if (error instanceof MergeNotFoundError) {
      return c.json({ error: error.message }, 400)
    }
    if (error instanceof AlreadyMergedError) {
      return c.json({ error: error.message }, 409)
    }
    throw error
  }
})

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

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