"use client";

import { useEffect, useState } from "react";
import { CheckCircle2, Timer, TriangleAlert } from "lucide-react";
import { Alert } from "@/components/ui/alert";
import { useI18n, useT } from "@/i18n";
import { formatDateTime } from "@/lib/format";
import type { Order } from "@/types/order";

/**
 * What is happening to an offer, in the back office's words.
 *
 * **An assignment is an offer, not a delivery under way.** The captain has to answer it, and if they
 * do not, the order goes back to the pool for somebody else. Before this, a dispatcher watched an
 * order they had just assigned turn back into `pending` with nothing on screen to say why — which
 * reads as the system losing the order rather than the rule working as designed.
 *
 * The window itself is an operations setting (`offer_timeout_s`), so nothing here hard-codes it: the
 * deadline arrives with the order and the countdown is drawn from it.
 */
export function OfferStatus({ order }: { order: Order }) {
  const t = useT();
  const { locale } = useI18n();

  const deadline = order.offer_expires_at ? new Date(order.offer_expires_at).getTime() : null;
  const left = useCountdown(order.status === "assigned" ? deadline : null);

  if (order.status === "assigned") {
    // No deadline on an order assigned before the offer flow existed: say what is true — it is
    // waiting — rather than inventing a countdown.
    if (deadline === null) {
      return (
        <Alert variant="info" title={t("orders.offer.waiting")}>
          {t("orders.offer.waitingHint")}
        </Alert>
      );
    }

    // Past the deadline the order has not moved yet only because the queued job has not run.
    // Saying "expired" is more honest than a frozen 0:00, and it explains the change that follows.
    if (left !== null && left <= 0) {
      return (
        <Alert variant="warning" title={t("orders.offer.lapsed")} icon={TriangleAlert}>
          {t("orders.offer.lapsedHint")}
        </Alert>
      );
    }

    return (
      <Alert variant="warning" title={t("orders.offer.waiting")} icon={Timer}>
        {t("orders.offer.countdown", {
          time: formatSeconds(left ?? 0),
          captain: order.driver?.name ?? t("orders.unassigned"),
        })}
        <span className="mt-1 block text-xs opacity-80">{t("orders.offer.countdownHint")}</span>
      </Alert>
    );
  }

  if (order.accepted_at) {
    return (
      <Alert variant="success" title={t("orders.offer.accepted")} icon={CheckCircle2}>
        {t("orders.offer.acceptedAt", {
          captain: order.driver?.name ?? "—",
          when: formatDateTime(order.accepted_at, locale),
        })}
      </Alert>
    );
  }

  return null;
}

/**
 * The same clock, compact enough for a table row.
 *
 * Renders nothing unless an offer is open, so a list of delivered orders does not grow a column of
 * dashes — and nothing for an order assigned before the offer flow existed, which has no deadline
 * to count to.
 */
export function OfferCountdown({ order }: { order: Order }) {
  const t = useT();
  const deadline = order.offer_expires_at ? new Date(order.offer_expires_at).getTime() : null;
  const left = useCountdown(order.status === "assigned" ? deadline : null);

  if (order.status !== "assigned" || left === null) return null;

  return left <= 0 ? (
    <p className="mt-1 text-[0.7rem] font-medium text-warning">{t("orders.offer.lapsedShort")}</p>
  ) : (
    <p className="mt-1 flex items-center gap-1 text-[0.7rem] text-muted-foreground">
      <Timer className="h-3 w-3" aria-hidden />
      {t("orders.offer.leftShort", { time: formatSeconds(left) })}
    </p>
  );
}

/**
 * Seconds left until a deadline, recomputed every second, or null when there is nothing to count.
 *
 * Driven by the deadline the server sent rather than by a duration ticking down from mount, so a
 * screen left open, a tab put to sleep or a clock that drifts all still show the same answer.
 */
function useCountdown(deadline: number | null): number | null {
  const [now, setNow] = useState(() => Date.now());

  useEffect(() => {
    if (deadline === null) return;

    const id = window.setInterval(() => setNow(Date.now()), 1000);

    return () => window.clearInterval(id);
  }, [deadline]);

  return deadline === null ? null : Math.ceil((deadline - now) / 1000);
}

/** `m:ss`, because a countdown read in whole seconds past a minute is arithmetic the reader does. */
function formatSeconds(seconds: number): string {
  const safe = Math.max(0, seconds);
  const minutes = Math.floor(safe / 60);

  return `${minutes}:${String(safe % 60).padStart(2, "0")}`;
}
