"use client";

import { useEffect, useRef } from "react";
import { resolveBaseUrl } from "@/core/api";
import { logger } from "@/core/logger";
import {
  type OrderStreamEvent,
  type OrderUpdateEventPayload,
} from "@customer-portal/domain/orders";

type OrderUpdateHandler = (event: OrderUpdateEventPayload) => void;

export function useOrderUpdates(orderId: string | undefined, onUpdate: OrderUpdateHandler) {
  const handlerRef = useRef<OrderUpdateHandler>(onUpdate);

  useEffect(() => {
    handlerRef.current = onUpdate;
  }, [onUpdate]);

  useEffect(() => {
    if (!orderId) {
      return;
    }

    let isCancelled = false;
    let eventSource: EventSource | null = null;
    let reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
    let reconnectAttempt = 0;

    const baseUrl = resolveBaseUrl();
    const url = new URL(`/api/orders/${orderId}/events`, baseUrl).toString();

    const getReconnectDelayMs = () => {
      // Exponential backoff with jitter (cap at 30s) to avoid thundering herd after outages/deploys.
      const baseMs = 1000;
      const maxMs = 30000;
      const exponential = Math.min(baseMs * Math.pow(2, reconnectAttempt), maxMs);
      const jitter = Math.floor(Math.random() * 500); // 0-500ms
      return Math.min(exponential + jitter, maxMs);
    };

    const connect = () => {
      if (isCancelled) return;

      logger.debug("Connecting to order updates stream", { orderId, url });
      const es = new EventSource(url, { withCredentials: true });
      eventSource = es;

      es.onopen = () => {
        reconnectAttempt = 0;
        logger.debug("Order updates stream connected", { orderId });
      };

      const handleMessage = (event: MessageEvent<string>) => {
        try {
          const parsed = JSON.parse(event.data) as OrderStreamEvent;
          if (!parsed || typeof parsed !== "object") {
            return;
          }

          if (parsed.event === "order.update") {
            const payload = parsed.data as OrderUpdateEventPayload;
            handlerRef.current?.(payload);
          }
        } catch (error) {
          logger.warn("Failed to parse order update event", { orderId, error });
        }
      };

      const handleError = (error: Event) => {
        logger.warn("Order updates stream disconnected", { orderId, error });
        es.close();
        eventSource = null;

        if (!isCancelled) {
          reconnectAttempt += 1;
          const delay = getReconnectDelayMs();
          reconnectTimeout = setTimeout(connect, delay);
        }
      };

      es.addEventListener("message", handleMessage as EventListener);
      es.onerror = handleError;
    };

    connect();

    return () => {
      isCancelled = true;
      if (eventSource) {
        eventSource.close();
      }
      if (reconnectTimeout) {
        clearTimeout(reconnectTimeout);
      }
    };
  }, [orderId]);
}
