"use client"

/**
 * Los avisos que le llegan al COMENSAL sobre su mesa, esté en la pantalla que
 * esté (menú, carrito, cuenta). Escucha SOLO los eventos de su `tableCode`.
 *
 * Nació en v1.72.0 para el cierre de cuenta (hasta ahí el «cobrada» iba solo
 * al staff y el teléfono se enteraba al refrescar, con un error en rojo). En
 * v1.73.0 se le sumaron el resto de los huecos de la auditoría de avisos:
 * la cuenta pedida por otro teléfono de la mesa, el mesero que ya atendió la
 * llamada, un pago parcial y un intent de pago vencido.
 */
import { useRef } from "react"
import { usePathname, useRouter } from "next/navigation"
import { useOrderMode } from "@/hooks/use-order-mode"
import { useRealtime } from "@/hooks/use-realtime"
import { toast } from "@/hooks/use-toast"
import type { TableItemAdjustedData, TableMovedData, TablePartialPaymentData, TablePaymentVoidedData, TableSessionClosedData } from "@/lib/realtime-events"

/**
 * Marcas «esto lo hice YO desde este teléfono», en sessionStorage y con
 * vencimiento. `sendToTable` no distingue emisores: el teléfono que pidió la
 * cuenta, llamó al mesero o pagó recibe el mismo evento que los demás de la
 * mesa, y sin esto se avisaba a sí mismo («la mesa pidió la cuenta» sobre su
 * propio modal). Nunca se decide por `paidBy`: eso silenciaba a toda la mesa.
 */
export type AccionMia = "pago" | "cuenta" | "llamada"
const VENCE_MS = 10 * 60_000

export function marcarAccionMia(accion: AccionMia, sessionId: string) {
  try {
    sessionStorage.setItem(`mesa-accion-${accion}`, `${sessionId}:${Date.now()}`)
  } catch {
    // sin storage no pasa nada: a lo sumo verá un aviso de más
  }
}

export function limpiarAccionMia(accion: AccionMia) {
  try {
    sessionStorage.removeItem(`mesa-accion-${accion}`)
  } catch {
    // ídem
  }
}

export function fueMia(accion: AccionMia, sessionId: string): boolean {
  try {
    const v = sessionStorage.getItem(`mesa-accion-${accion}`)
    if (!v) return false
    const [id, ts] = v.split(":")
    return id === sessionId && Date.now() - Number(ts) < VENCE_MS
  } catch {
    return false
  }
}

/** La cuenta que este teléfono tiene abierta (la fija la pantalla de cuenta). */
export function marcarMiCuenta(sessionId: string) {
  try {
    sessionStorage.setItem("mesa-session-id", sessionId)
  } catch {
    // ídem
  }
}

function miCuenta(): string | null {
  try {
    return sessionStorage.getItem("mesa-session-id")
  } catch {
    return null
  }
}

/** Compatibilidad: el modal de pago marca «pagué yo». */
export const marcarPagueYo = (sessionId: string) => marcarAccionMia("pago", sessionId)

export function TableSessionClosedWatcher({ sedeSlug }: { sedeSlug: string }) {
  const orderMode = useOrderMode()
  const router = useRouter()
  const pathname = usePathname()
  const avisado = useRef<string | null>(null)
  const activo = orderMode.isLoaded && orderMode.isTable && !!orderMode.tableCode

  useRealtime({
    role: "customer",
    tableCode: activo ? orderMode.tableCode : undefined,
    autoConnect: activo,
    onEvent: (event) => {
      if (event.type === "table:session_closed") {
        const data = event.data as TableSessionClosedData
        if (avisado.current === data.sessionId) return
        avisado.current = data.sessionId

        // Este teléfono ya vio el modal de pago: no repetirle. Se decide por
        // TELÉFONO (marca en sessionStorage), no por `paidBy`: con `paidBy`
        // se silenciaba a toda la mesa y los demás quedaban en una cuenta
        // fantasma (hueco #2 de la auditoría del 2026-09-02).
        const fuiYo = data.status === "PAID" && data.paidBy === "customer" && fueMia("pago", data.sessionId)
        orderMode.clearMode()
        limpiarAccionMia("pago")
        // Pagó desde este teléfono: ya ve el modal de éxito, que al cerrarse lo
        // manda a la portada. Ni toast ni redirección encima.
        if (fuiYo) return
        if (data.status === "PAID") {
          toast({
            title: "Tu cuenta fue cobrada",
            description:
              data.paidBy === "customer"
                ? `Alguien de la mesa ${data.tableNumber} pagó la cuenta desde su teléfono. ¡Gracias por tu visita!`
                : `Mesa ${data.tableNumber}. ¡Gracias por tu visita, te esperamos pronto!`,
            duration: 12000,
          })
        } else {
          toast({
            title: "Tu cuenta fue cerrada",
            description: `El personal cerró la cuenta de la mesa ${data.tableNumber}. Si fue un error, avísale a tu mesero.`,
            duration: 12000,
          })
        }
        router.push(`/${sedeSlug}`)
        return
      }

      if (event.type === "table:bill_requested") {
        const data = event.data as { tableNumber: string; sessionId: string }
        // La pidió este mismo teléfono: ya tiene el modal abierto.
        if (fueMia("cuenta", data.sessionId)) return
        toast({
          title: "La mesa pidió la cuenta",
          description: `Ya no se pueden agregar pedidos a la mesa ${data.tableNumber}. Si falta algo, avísale al mesero.`,
          duration: 10000,
        })
        return
      }

      if (event.type === "table:call_cleared") {
        // Solo al teléfono que llamó; a los demás de la mesa no les dice nada.
        const cuenta = miCuenta()
        if (!cuenta || !fueMia("llamada", cuenta)) return
        limpiarAccionMia("llamada")
        toast({
          title: "Tu mesero ya va en camino",
          description: "El personal atendió tu llamada.",
        })
        return
      }

      if (event.type === "table:partial_payment") {
        const data = event.data as TablePartialPaymentData
        // El teléfono que acaba de pagar su parte ya ve su propio modal.
        if (data.paidBy === "customer" && fueMia("pago", data.sessionId)) return
        toast({
          title: data.dinerName ? `${data.dinerName} ya pagó su parte` : "Se registró un pago",
          description:
            data.remaining > 0
              ? `Pagado: $${data.amount.toFixed(2)}. Falta por cobrar: $${data.remaining.toFixed(2)}.`
              : `Pagado: $${data.amount.toFixed(2)}.`,
          duration: 10000,
        })
        return
      }

      if (event.type === "table:moved") {
        // Gerencia pasó la cuenta a otra mesa: este teléfono la sigue con el
        // código nuevo (el token es el mismo) y, si está en la cuenta o el
        // menú, se va a la URL de la mesa nueva.
        const data = event.data as TableMovedData
        const cuenta = miCuenta()
        if (cuenta && cuenta !== data.sessionId) return
        orderMode.setTableMode(data.toTableCode, orderMode.sessionToken)
        toast({
          title: `Tu cuenta pasó a la mesa ${data.toTableNumber}`,
          description: "Sigue siendo la misma cuenta. Puedes seguir pidiendo desde este teléfono.",
          duration: 10000,
        })
        if (pathname?.includes("/cuenta")) router.replace(`/${sedeSlug}/cuenta?mesa=${data.toTableCode}`)
        else if (pathname?.includes("/menu")) router.replace(`/${sedeSlug}/menu?mesa=${data.toTableCode}`)
        return
      }

      if (event.type === "table:payment_voided") {
        const data = event.data as TablePaymentVoidedData
        const cuenta = miCuenta()
        if (cuenta && cuenta !== data.sessionId) return
        toast({
          title: `Se anuló un pago de $${data.amount.toFixed(2)}`,
          description: `${data.motivo}. Falta por cobrar $${data.remaining.toFixed(2)}.`,
          duration: 10000,
        })
        return
      }

      if (event.type === "table:item_adjusted") {
        // Gerencia anuló, dio de cortesía o descontó algo de ESTA cuenta.
        const data = event.data as TableItemAdjustedData
        const cuenta = miCuenta()
        if (cuenta && cuenta !== data.sessionId) return
        const que =
          data.tipo === "VOID"
            ? `Se quitó ${data.cantidad} × ${data.itemName} de tu cuenta`
            : data.tipo === "COMP"
              ? `${data.cantidad} × ${data.itemName} va por cuenta de la casa`
              : `${data.itemName} tiene ${data.pct}% de descuento`
        toast({
          title: que,
          description: `Mesa ${data.tableNumber}. Tu cuenta queda en $${data.nuevoTotal.toFixed(2)}.`,
          duration: 10000,
        })
        return
      }

      if (event.type === "payment:intent_expired") {
        // Un intent viejo de otra cuenta en la misma mesa no es asunto de este teléfono.
        const data = event.data as { sessionId: string }
        const cuenta = miCuenta()
        if (cuenta && cuenta !== data.sessionId) return
        toast({
          title: "El pago venció sin completarse",
          description: "No se cobró nada. Vuelve a intentarlo desde Mi Cuenta o pide la cuenta al mesero.",
          variant: "destructive",
          duration: 12000,
        })
      }
    },
  })

  return null
}
