/**
 * `AgentLimitBadge` — presentational badge for an agent's session-limit state
 * (ARCHITECTURE §21). All limit *state* is computed in {@link useAgents}; this
 * component only renders it and owns the 1 s countdown clock (a pure UI concern).
 *
 * It shows:
 *  - "limité jusqu'à HH:MM" when the reset time is known, "limité" otherwise;
 *  - a live countdown + an "Annuler la reprise" button while an auto-resume is
 *    armed (`resumeFireAt`);
 *  - a "heure inconnue" human-net note (level 3) when the limit is only
 *    *suspected* with no reliable time — IdeA never resumes blind.
 */

import { useEffect, useState } from "react";

import { Button, Input, cn } from "@/shared";
import type { AgentLimitState } from "./useAgents";

/**
 * Converts a `<input type="time">` value (`"HH:MM"`) into an epoch-ms instant on
 * the same calendar day as `now`. Returns `null` for an empty/malformed value so
 * the caller can ignore an incomplete entry.
 *
 * No future/past guard on purpose: an instant earlier than `now` is left as-is —
 * the backend clamps a past time to "now" (⇒ immediate resume), so the front
 * needs no strict validation.
 */
export function timeInputToEpochMs(value: string, now: number): number | null {
  const match = /^(\d{1,2}):(\d{2})$/.exec(value.trim());
  if (!match) return null;
  const hours = Number(match[1]);
  const minutes = Number(match[2]);
  if (hours > 23 || minutes > 59) return null;
  const d = new Date(now);
  d.setHours(hours, minutes, 0, 0);
  return d.getTime();
}

/** Formats an epoch-ms instant as a local `HH:MM` wall-clock label. */
export function formatResetTime(epochMs: number): string {
  return new Date(epochMs).toLocaleTimeString([], {
    hour: "2-digit",
    minute: "2-digit",
  });
}

/**
 * Formats a remaining duration (ms) as a compact countdown: `Xm Ys` (or `Ys`
 * under a minute). Clamped at zero — a past deadline reads `0s`.
 */
export function formatCountdown(remainingMs: number): string {
  const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1000));
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;
  return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
}

export interface AgentLimitBadgeProps {
  /** The agent's limit state (from {@link useAgents.limitByAgent}). */
  state: AgentLimitState;
  /** Invoked when the user clicks "Annuler la reprise". */
  onCancelResume: () => void;
  /**
   * Human net (level 3): invoked with the chosen wake-up instant (epoch-ms) when
   * the user submits the resume-time form on a suspected-without-time limit.
   */
  onSetResumeAt: (resetsAtMs: number) => void;
  /** Disables the actions (e.g. while another request is in flight). */
  busy?: boolean;
}

export function AgentLimitBadge({
  state,
  onCancelResume,
  onSetResumeAt,
  busy = false,
}: AgentLimitBadgeProps) {
  const { limitedUntil, resumeFireAt, suspected } = state;

  // Tick a local clock once per second only while a resume countdown is armed,
  // so the displayed remaining time stays fresh without a global timer.
  const [now, setNow] = useState(() => Date.now());
  useEffect(() => {
    if (resumeFireAt === undefined) return;
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, [resumeFireAt]);

  // Local resume-time entry (human net form). Bound to a `time` input.
  const [resumeTime, setResumeTime] = useState("");

  // The human-net form shows only when the limit is *suspected* with neither a
  // reliable reset time nor an armed resume — IdeA must ask before resuming.
  const needsResumeTime =
    suspected === true &&
    limitedUntil === undefined &&
    resumeFireAt === undefined;

  function handleSubmitResumeTime(e: React.FormEvent) {
    e.preventDefault();
    const epochMs = timeInputToEpochMs(resumeTime, Date.now());
    if (epochMs === null) return;
    onSetResumeAt(epochMs);
    setResumeTime("");
  }

  const limitLabel =
    limitedUntil !== undefined
      ? `limité jusqu'à ${formatResetTime(limitedUntil)}`
      : "limité";

  return (
    <span className="flex min-w-0 flex-wrap items-center gap-2">
      <span
        aria-label="session limit"
        title={
          suspected
            ? "Limite de session détectée sans heure fiable"
            : "Limite de session atteinte"
        }
        className={cn(
          "rounded-full px-2 py-0.5 text-xs font-medium",
          "bg-danger/20 text-danger",
        )}
      >
        {limitLabel}
      </span>

      {needsResumeTime && (
        // Human net (level 3, §21.1): the limit is suspected with no reliable
        // time. IdeA never resumes blind — ask the user for a resume time, then
        // arm it via `set_resume_at`. A past time is clamped to "now" by the
        // backend (⇒ immediate resume), so no strict validation is needed here.
        <form
          onSubmit={handleSubmitResumeTime}
          className="flex items-center gap-2"
          aria-label="resume time form"
        >
          <span className="text-xs text-muted" role="note">
            heure inconnue
          </span>
          <Input
            type="time"
            aria-label="resume time"
            value={resumeTime}
            disabled={busy}
            onChange={(e) => setResumeTime(e.target.value)}
            className="h-8 w-28 text-xs"
          />
          <Button
            type="submit"
            size="sm"
            variant="primary"
            aria-label="schedule resume"
            disabled={busy || resumeTime.trim() === ""}
          >
            Programmer la reprise
          </Button>
        </form>
      )}

      {resumeFireAt !== undefined && (
        <span className="flex items-center gap-2">
          <span aria-label="resume countdown" className="text-xs text-muted">
            reprise dans {formatCountdown(resumeFireAt - now)}
          </span>
          <Button
            size="sm"
            variant="ghost"
            aria-label="cancel resume"
            disabled={busy}
            onClick={onCancelResume}
          >
            Annuler la reprise
          </Button>
        </span>
      )}
    </span>
  );
}
