/**
 * RecoveryBanner — full-width warning shown when fail2ban stopped responding
 * shortly after a jail was activated (indicating the new jail config may be
 * invalid).
 *
 * Polls ``GET /api/config/pending-recovery`` every 10 seconds and renders a
 * dismissible ``MessageBar`` when an unresolved crash record is present.
 * The "Disable & Restart" button calls the rollback endpoint to disable the
 * offending jail and attempt to restart fail2ban.
 */

import { useCallback, useEffect, useRef, useState } from "react";
import {
  Button,
  MessageBar,
  MessageBarActions,
  MessageBarBody,
  MessageBarTitle,
  Spinner,
  tokens,
} from "@fluentui/react-components";
import { useNavigate } from "react-router-dom";
import { fetchPendingRecovery, rollbackJail } from "../../api/config";
import type { PendingRecovery } from "../../types/config";

const POLL_INTERVAL_MS = 10_000;

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

/**
 * Recovery banner that polls for pending crash-recovery records.
 *
 * Mount this once at the layout level so it is visible across all pages
 * while a recovery is pending.
 *
 * @returns A MessageBar element, or null when nothing is pending.
 */
export function RecoveryBanner(): React.JSX.Element | null {
  const navigate = useNavigate();
  const [pending, setPending] = useState<PendingRecovery | null>(null);
  const [rolling, setRolling] = useState(false);
  const [rollbackError, setRollbackError] = useState<string | null>(null);
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);

  const poll = useCallback((): void => {
    fetchPendingRecovery()
      .then((record) => {
        // Hide the banner once fail2ban has recovered on its own.
        if (record?.recovered) {
          setPending(null);
        } else {
          setPending(record);
        }
      })
      .catch(() => { /* ignore network errors — will retry */ });
  }, []);

  // Start polling on mount.
  useEffect(() => {
    poll();
    timerRef.current = setInterval(poll, POLL_INTERVAL_MS);
    return (): void => {
      if (timerRef.current !== null) clearInterval(timerRef.current);
    };
  }, [poll]);

  const handleRollback = useCallback((): void => {
    if (!pending || rolling) return;
    setRolling(true);
    setRollbackError(null);
    rollbackJail(pending.jail_name)
      .then(() => {
        setPending(null);
      })
      .catch((err: unknown) => {
        const msg = err instanceof Error ? err.message : String(err);
        setRollbackError(msg);
      })
      .finally(() => {
        setRolling(false);
      });
  }, [pending, rolling]);

  const handleViewDetails = useCallback((): void => {
    navigate("/config");
  }, [navigate]);

  if (pending === null) return null;

  return (
    <div
      style={{
        flexShrink: 0,
        paddingLeft: tokens.spacingHorizontalM,
        paddingRight: tokens.spacingHorizontalM,
        paddingTop: tokens.spacingVerticalXS,
        paddingBottom: tokens.spacingVerticalXS,
      }}
      role="alert"
    >
      <MessageBar intent="error">
        <MessageBarBody>
          <MessageBarTitle>fail2ban Stopped After Jail Activation</MessageBarTitle>
          fail2ban stopped responding after activating jail{" "}
          <strong>{pending.jail_name}</strong>. The jail&apos;s configuration
          may be invalid.
          {rollbackError && (
            <div style={{ marginTop: tokens.spacingVerticalXS, color: tokens.colorStatusDangerForeground1 }}>
              Rollback failed: {rollbackError}
            </div>
          )}
        </MessageBarBody>
        <MessageBarActions>
          <Button
            appearance="primary"
            size="small"
            icon={rolling ? <Spinner size="tiny" /> : undefined}
            disabled={rolling}
            onClick={handleRollback}
          >
            {rolling ? "Disabling…" : "Disable & Restart"}
          </Button>
          <Button
            appearance="secondary"
            size="small"
            onClick={handleViewDetails}
          >
            View Logs
          </Button>
        </MessageBarActions>
      </MessageBar>
    </div>
  );
}
