"use client"

import { useEffect, useRef, useCallback } from "react"
import { useDispatch, useSelector } from "react-redux"
import { io, Socket } from "socket.io-client"
import { toast } from "sonner"
import { applySocketStatusUpdate, prependNewOrder } from "@/src/state/order"
import type { FoodOrderStatus, FoodOrderSummary, FoodOrderDetail } from "@/src/state/order"
import { selectCurrentRestaurant, selectCurrentToken } from "@/src/state/auth"
import type { AppDispatch } from "@/src/state/store"

const SOCKET_URL = process.env.NEXT_PUBLIC_SOCKET_URL ?? "http://localhost:4000"
const API_URL = process.env.NEXT_PUBLIC_API ?? "http://localhost:4000/api/v1.1"

type SocketOrderNewPayload = {
  orderId: string
  orderNumber: string
  items: {
    menuItemId: string
    quantity: number
    unitPrice: number
    totalPrice: number
    specialNote: string | null
  }[]
  total: number
  deliveryAddress: string
  timestamp: number
}

type SocketStatusUpdatedPayload = {
  orderId: string
  restaurantSlug: string
  status: FoodOrderStatus
  userId: string | null
  delivererId: string | null
  timestamp: number
}

export function useFoodOrderSocket() {
  const dispatch = useDispatch<AppDispatch>()
  const restaurant = useSelector(selectCurrentRestaurant)
  const token = useSelector(selectCurrentToken)
  const socketRef = useRef<Socket | null>(null)

  const joinOrderRoom = useCallback(
    (orderId: string) => {
      if (!restaurant?.slug) return
      socketRef.current?.emit("join-order-room", {
        restaurantSlug: restaurant.slug,
        orderId,
      })
    },
    [restaurant],
  )

  const leaveOrderRoom = useCallback(
    (orderId: string) => {
      if (!restaurant?.slug) return
      socketRef.current?.emit("leave-order-room", {
        restaurantSlug: restaurant.slug,
        orderId,
      })
    },
    [restaurant],
  )

  useEffect(() => {
    if (!restaurant || !token) return

    const connect = () => {
      const socket = io(`${SOCKET_URL}/food-delivery`, {
        query: {
          userId: restaurant.id,
          userType: "restaurant",
          restaurantSlug: restaurant.slug ?? restaurant.id,
        },
        transports: ["websocket"],
      })

      socketRef.current = socket

      socket.on("order:new", (data: SocketOrderNewPayload) => {
        toast.info(`Nouvelle commande ${data.orderNumber}`, {
          description: `${data.items.length} article(s) · ${data.total.toLocaleString("fr-FR")} FCFA`,
        })

        fetch(`${API_URL}/food-orders/restaurant/${data.orderId}`, {
          headers: { Authorization: `Bearer ${token}` },
        })
          .then((r) => r.json())
          .then((json: { data: FoodOrderDetail }) => {
            const detail = json.data
            const summary: FoodOrderSummary = {
              id: detail.id,
              orderNumber: detail.orderNumber,
              status: detail.status,
              subtotal: detail.subtotal,
              deliveryFee: detail.deliveryFee,
              total: detail.total,
              neighbourhood: detail.neighbourhood,
              paymentMethod: detail.paymentMethod,
              paymentStatus: detail.paymentStatus,
              createdAt: detail.createdAt,
              user: { id: detail.user.id, fullName: detail.user.fullName },
              items: detail.items.map((i) => ({
                quantity: i.quantity,
                unitPrice: i.unitPrice,
                totalPrice: i.totalPrice,
                specialNote: i.specialNote,
                menuItem: { name: i.menuItem.name },
              })),
            }
            dispatch(prependNewOrder(summary))
          })
          .catch(() => {
            const fallback: FoodOrderSummary = {
              id: data.orderId,
              orderNumber: data.orderNumber,
              status: "ORDER_PLACED",
              subtotal: data.total,
              deliveryFee: 0,
              total: data.total,
              neighbourhood: null,
              paymentMethod: "PAY_ON_DELIVERY",
              paymentStatus: "PENDING",
              createdAt: new Date(data.timestamp).toISOString(),
              user: { id: "", fullName: "—" },
              items: data.items.map((i) => ({
                quantity: i.quantity,
                unitPrice: i.unitPrice,
                totalPrice: i.totalPrice,
                specialNote: i.specialNote,
                menuItem: { name: "" },
              })),
            }
            dispatch(prependNewOrder(fallback))
          })
      })

      socket.on("order:status-updated", (data: SocketStatusUpdatedPayload) => {
        dispatch(applySocketStatusUpdate({ orderId: data.orderId, status: data.status }))
      })

      return socket
    }

    const socket = connect()

    const now = new Date()
    const midnight = new Date(now)
    midnight.setHours(24, 0, 0, 0)
    const msUntilMidnight = midnight.getTime() - now.getTime()

    const midnightTimer = setTimeout(() => {
      socket.disconnect()
      connect()
    }, msUntilMidnight)

    return () => {
      clearTimeout(midnightTimer)
      socket.disconnect()
      socketRef.current = null
    }
  }, [restaurant, token, dispatch])

  return { socketRef, joinOrderRoom, leaveOrderRoom }
}
