import { Text, Tooltip, UnstyledButton } from "@mantine/core";
import { useQuery } from "@tanstack/react-query";
import { AlertTriangle, ChevronRight } from "lucide-react";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

import { useAuth } from "@/auth/useAuth";
import { canSeeDocReviewAlert } from "@/lib/permissions";
import { api } from "@/services/api";

/**
 * Booking-request statuses that count as "nobody decided yet". These are the
 * exact statuses the window engine expires when document review ends
 * (findUnacceptedForRouteDay), so the deep-linked list shows precisely the
 * requests the countdown is warning about.
 */
const UNDECIDED_STATUSES = [
  "OPERATION_REQUESTED",
  "OPERATION_REQUEST_PENDING",
  "OPERATION_CHANGES_REQUESTED",
  "OPERATION_PRICE_PENDING_CONFIRM",
].join(",");

const pendingRequestsHref = (tradeDirection: string) =>
  `/dashboard/booking-requests?statuses=${UNDECIDED_STATUSES}&tradeDirection=${tradeDirection}`;

/** mm:ss (or h:mm:ss past an hour), fixed width so the pill never jitters. */
function formatRemaining(ms: number): string {
  const total = Math.max(0, Math.floor(ms / 1000));
  const hours = Math.floor(total / 3600);
  const minutes = Math.floor((total % 3600) / 60);
  const seconds = total % 60;
  const mm = String(minutes).padStart(2, "0");
  const ss = String(seconds).padStart(2, "0");
  return hours > 0 ? `${hours}:${mm}:${ss}` : `${mm}:${ss}`;
}

/**
 * Header alarm for the document-review deadline. Runs for the whole review
 * phase — from the moment it opens until the clock runs out — whenever requests
 * are still undecided. Everything left pending at the deadline is expired
 * automatically, so staff get the full window to accept or reject rather than
 * only its back half. Clicking opens the booking requests already filtered to
 * those undecided requests.
 */
export default function DocReviewAlertButton() {
  const navigate = useNavigate();
  const { user } = useAuth();

  const { data: alert } = useQuery({
    ...api.trainScheduling.docReviewAlert.queryOptions(),
    // Dedicated permission: only the position types granted it are alarmed.
    enabled: canSeeDocReviewAlert(user),
    // The window engine ticks every 10s; a minute is close enough for a header
    // chip — the countdown itself runs locally.
    refetchInterval: 60_000,
  });

  const deadlineMs = alert ? new Date(alert.docReviewEndsAt).getTime() : 0;
  const [remaining, setRemaining] = useState(() => deadlineMs - Date.now());

  useEffect(() => {
    if (!deadlineMs) return;
    const tick = () => setRemaining(deadlineMs - Date.now());
    tick();
    const id = window.setInterval(tick, 1000);
    return () => window.clearInterval(id);
  }, [deadlineMs]);

  if (!alert) return null;
  // Alarm for the WHOLE review phase, from the moment it opens: anything still
  // undecided when the clock runs out is expired automatically, so staff need
  // the full window to act, not the back half of it. The endpoint only returns
  // a schedule that is in DOC_REVIEW with undecided requests behind it, so the
  // remaining check just hides the pill once the deadline passes.
  if (remaining <= 0) return null;

  const requestLabel = alert.pendingCount === 1 ? "request" : "requests";

  return (
    <Tooltip
      withArrow
      openDelay={200}
      multiline
      w={260}
      label={`Document review ends in ${formatRemaining(remaining)}. ${alert.pendingCount} ${alert.tradeDirection.toLowerCase()} booking ${requestLabel} ${alert.pendingCount === 1 ? "is" : "are"} still neither accepted nor rejected and will expire automatically. Click to review them.`}
    >
      <UnstyledButton
        onClick={() => navigate(pendingRequestsHref(alert.tradeDirection))}
        aria-label={`${alert.pendingCount} import booking ${requestLabel} awaiting a decision — document review ends in ${formatRemaining(remaining)}`}
        className="group flex h-9 shrink-0 items-center gap-2 rounded-full pl-2.5 pr-2 transition-transform hover:scale-[1.02]"
        // Inline, not Tailwind: Mantine's UnstyledButton resets the background
        // in unlayered CSS, which beats a `@layer utilities` class whatever its
        // specificity — `bg-red-600` alone renders the pill white.
        style={{
          background: "var(--mantine-color-red-6)",
          border: "1px solid var(--mantine-color-red-7)",
          color: "#fff",
          boxShadow: "0 2px 10px rgba(220, 38, 38, 0.35)",
        }}
      >
        {/* Live dot: a ping ring behind a solid core, so the pill reads as
            active without animating the whole chip. */}
        <span className="relative flex size-2 shrink-0">
          <span className="absolute inline-flex size-full animate-ping rounded-full bg-white opacity-75" />
          <span className="relative inline-flex size-2 rounded-full bg-white" />
        </span>

        <AlertTriangle size={15} strokeWidth={2.2} className="shrink-0" />

        <Text
          size="xs"
          fw={700}
          visibleFrom="sm"
          className="whitespace-nowrap text-white!"
        >
          {alert.pendingCount} undecided
        </Text>

        <Text
          size="xs"
          fw={700}
          className="text-white!"
          style={{ fontVariantNumeric: "tabular-nums", letterSpacing: "0.02em" }}
        >
          {formatRemaining(remaining)}
        </Text>

        <ChevronRight
          size={14}
          strokeWidth={2.2}
          className="shrink-0 opacity-80 transition-transform group-hover:translate-x-0.5"
        />
      </UnstyledButton>
    </Tooltip>
  );
}
