import { Router, type Request, type Response } from 'express'
import { z } from 'zod'
import { prisma } from '../../infra/database/prisma'
import { normalizeJid } from '../../shared/utils/whatsapp'
import { invalidateChatListCache } from '../chats/chat.cache'

export function buildContactRoutes(): Router {
  const router = Router()

  // ── GET /api/contacts/stats/overview — deve vir ANTES de /:id ─────────────
  router.get('/stats/overview', async (req: Request, res: Response) => {
    const tenantId = req.tenantId!
    const instanceId = req.query['instanceId'] as string | undefined

    const where: Record<string, unknown> = { tenantId }
    if (instanceId) where['instanceId'] = instanceId

    const [total, blocked, flagged] = await Promise.all([
      prisma.contact.count({ where }),
      prisma.contact.count({ where: { ...where, isBlocked: true } }),
      prisma.contact.count({ where: { ...where, flagRestricao: true } }),
    ])

    res.json({ total, blocked, flagged, active: total - blocked })
  })

  // ── GET /api/contacts — lista paginada ────────────────────────────────────
  router.get('/', async (req: Request, res: Response) => {
    const tenantId = req.tenantId!
    const instanceId = req.query['instanceId'] as string | undefined
    const search    = req.query['search']     as string | undefined
    const blocked   = req.query['blocked']    as string | undefined
    const limit     = Math.min(Number(req.query['limit']  ?? 50), 200)
    const offset    = Number(req.query['offset'] ?? 0)

    const where: Record<string, unknown> = { tenantId }
    if (instanceId) where['instanceId'] = instanceId
    if (blocked === 'true')  where['isBlocked'] = true
    if (blocked === 'false') where['isBlocked'] = false
    if (search) {
      where['OR'] = [
        { name:         { contains: search, mode: 'insensitive' } },
        { verifiedName: { contains: search, mode: 'insensitive' } },
        { notify:       { contains: search, mode: 'insensitive' } },
        { phone:        { contains: search } },
        { jid:          { contains: search } },
      ]
    }

    const [total, contacts] = await Promise.all([
      prisma.contact.count({ where }),
      prisma.contact.findMany({
        where,
        // Tiebreaker por id é obrigatório: muitos contatos compartilham o mesmo
        // updatedAt (bulk sync), e sem segunda coluna a paginação por OFFSET
        // devolve linhas sobrepostas entre páginas — quebra "carregar mais".
        orderBy: [{ updatedAt: 'desc' }, { id: 'asc' }],
        take: limit,
        skip: offset,
        select: {
          id: true,
          instanceId: true,
          jid: true,
          name: true,
          verifiedName: true,
          notify: true,
          phone: true,
          avatarUrl: true,
          scoreReputacao: true,
          flagRestricao: true,
          isBlocked: true,
          createdAt: true,
          updatedAt: true,
        },
      }),
    ])

    res.json({
      total,
      contacts: contacts.map(c => ({
        ...c,
        displayName: c.name || c.verifiedName || c.notify || (c.phone ? `+${c.phone}` : normalizeJid(c.jid).split('@')[0])
      }))
    })
  })

  // ── GET /api/contacts/:id — detalhe ──────────────────────────────────────
  router.get('/:id', async (req: Request, res: Response) => {
    const tenantId = req.tenantId!
    const id = req.params['id'] as string

    const contact = await prisma.contact.findFirst({
      where: { id, tenantId },
      include: {
        chats: {
          orderBy: { lastMessageAt: 'desc' },
          take: 1,
          select: { id: true, unreadCount: true, lastMessageAt: true },
        },
      },
    })

    if (!contact) {
      res.status(404).json({ error: 'Contato não encontrado' })
      return
    }

    res.json(contact)
  })

  // ── PATCH /api/contacts/:id — editar nome / bloquear ─────────────────────
  router.patch('/:id', async (req: Request, res: Response) => {
    const tenantId = req.tenantId!
    const id = req.params['id'] as string

    const schema = z.object({
      name:      z.string().min(1).max(255).optional(),
      isBlocked: z.boolean().optional(),
    })

    let body: z.infer<typeof schema>
    try {
      body = schema.parse(req.body)
    } catch (err: any) {
      res.status(400).json({ error: err.errors ?? err.message })
      return
    }

    const existing = await prisma.contact.findFirst({ where: { id, tenantId } })
    if (!existing) {
      res.status(404).json({ error: 'Contato não encontrado' })
      return
    }

    const updated = await prisma.contact.update({ where: { id }, data: body })

    if (body.name && existing.instanceId) {
      invalidateChatListCache(tenantId, existing.instanceId).catch(() => {})
    }

    res.json(updated)
  })

  // ── DELETE /api/contacts/:id ──────────────────────────────────────────────
  router.delete('/:id', async (req: Request, res: Response) => {
    const tenantId = req.tenantId!
    const id = req.params['id'] as string

    const existing = await prisma.contact.findFirst({ where: { id, tenantId } })
    if (!existing) {
      res.status(404).json({ error: 'Contato não encontrado' })
      return
    }

    // Desvincular chats antes de deletar o contato
    await prisma.chat.updateMany({
      where: { contactId: id },
      data: { contactId: null },
    })

    await prisma.contact.delete({ where: { id } })

    if (existing.instanceId) {
      invalidateChatListCache(tenantId, existing.instanceId).catch(() => {})
    }

    res.status(204).send()
  })

  return router
}
