/**
 * ServerTab — fail2ban server-level settings editor.
 *
 * Provides form fields for live server settings (log level, log target,
 * DB purge age, DB max matches), action buttons (flush logs, reload fail2ban,
 * restart fail2ban), world map color threshold configuration, and service
 * health + log viewer.
 */

import { useCallback, useEffect, useMemo, useState } from "react";
import {
  Button,
  Field,
  Input,
  MessageBar,
  MessageBarBody,
  Select,
  Skeleton,
  SkeletonItem,
  Text,
  tokens,
} from "@fluentui/react-components";
import {
  DocumentArrowDown24Regular,
  ArrowSync24Regular,
} from "@fluentui/react-icons";
import { ApiError } from "../../api/client";
import type { ServerSettingsUpdate, MapColorThresholdsResponse, MapColorThresholdsUpdate } from "../../types/config";
import { useServerSettings } from "../../hooks/useConfig";
import { useAutoSave } from "../../hooks/useAutoSave";
import {
  fetchMapColorThresholds,
  updateMapColorThresholds,
  reloadConfig,
  restartFail2Ban,
} from "../../api/config";
import { AutoSaveIndicator } from "./AutoSaveIndicator";
import { ServerHealthSection } from "./ServerHealthSection";
import { useConfigStyles } from "./configStyles";

/** Available fail2ban log levels in descending severity order. */
const LOG_LEVELS = ["CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"];

/**
 * Tab component for editing live fail2ban server settings.
 *
 * @returns JSX element.
 */
export function ServerTab(): React.JSX.Element {
  const styles = useConfigStyles();
  const { settings, loading, error, updateSettings, flush } =
    useServerSettings();
  const [logLevel, setLogLevel] = useState("");
  const [logTarget, setLogTarget] = useState("");
  const [dbPurgeAge, setDbPurgeAge] = useState("");
  const [dbMaxMatches, setDbMaxMatches] = useState("");
  const [flushing, setFlushing] = useState(false);
  const [msg, setMsg] = useState<{ text: string; ok: boolean } | null>(null);

  // Reload/Restart state
  const [isReloading, setIsReloading] = useState(false);
  const [isRestarting, setIsRestarting] = useState(false);

  // Map color thresholds
  const [mapThresholds, setMapThresholds] = useState<MapColorThresholdsResponse | null>(null);
  const [mapThresholdHigh, setMapThresholdHigh] = useState("");
  const [mapThresholdMedium, setMapThresholdMedium] = useState("");
  const [mapThresholdLow, setMapThresholdLow] = useState("");
  const [mapLoadError, setMapLoadError] = useState<string | null>(null);

  const effectiveLogLevel = logLevel || settings?.log_level || "";
  const effectiveLogTarget = logTarget || settings?.log_target || "";
  const effectiveDbPurgeAge =
    dbPurgeAge || (settings ? String(settings.db_purge_age) : "");
  const effectiveDbMaxMatches =
    dbMaxMatches || (settings ? String(settings.db_max_matches) : "");

  const updatePayload = useMemo<ServerSettingsUpdate>(() => {
    const update: ServerSettingsUpdate = {};
    if (effectiveLogLevel) update.log_level = effectiveLogLevel;
    if (effectiveLogTarget) update.log_target = effectiveLogTarget;
    if (effectiveDbPurgeAge)
      update.db_purge_age = Number(effectiveDbPurgeAge);
    if (effectiveDbMaxMatches)
      update.db_max_matches = Number(effectiveDbMaxMatches);
    return update;
  }, [effectiveLogLevel, effectiveLogTarget, effectiveDbPurgeAge, effectiveDbMaxMatches]);

  const { status: saveStatus, errorText: saveErrorText, retry: retrySave } =
    useAutoSave(updatePayload, updateSettings);

  const handleFlush = useCallback(async () => {
    setFlushing(true);
    setMsg(null);
    try {
      const result = await flush();
      setMsg({ text: `Logs flushed: ${result}`, ok: true });
    } catch (err: unknown) {
      setMsg({
        text: err instanceof ApiError ? err.message : "Flush failed.",
        ok: false,
      });
    } finally {
      setFlushing(false);
    }
  }, [flush]);

  const handleReload = useCallback(async () => {
    setIsReloading(true);
    setMsg(null);
    try {
      await reloadConfig();
      setMsg({ text: "fail2ban reloaded successfully", ok: true });
    } catch (err: unknown) {
      setMsg({
        text: err instanceof ApiError ? err.message : "Reload failed.",
        ok: false,
      });
    } finally {
      setIsReloading(false);
    }
  }, []);

  const handleRestart = useCallback(async () => {
    setIsRestarting(true);
    setMsg(null);
    try {
      await restartFail2Ban();
      setMsg({ text: "fail2ban restart initiated", ok: true });
    } catch (err: unknown) {
      setMsg({
        text: err instanceof ApiError ? err.message : "Restart failed.",
        ok: false,
      });
    } finally {
      setIsRestarting(false);
    }
  }, []);

  // Load map color thresholds on mount.
  const loadMapThresholds = useCallback(async (): Promise<void> => {
    try {
      const data = await fetchMapColorThresholds();
      setMapThresholds(data);
      setMapThresholdHigh(String(data.threshold_high));
      setMapThresholdMedium(String(data.threshold_medium));
      setMapThresholdLow(String(data.threshold_low));
      setMapLoadError(null);
    } catch (err) {
      setMapLoadError(
        err instanceof ApiError ? err.message : "Failed to load map color thresholds",
      );
    }
  }, []);

  useEffect(() => {
    void loadMapThresholds();
  }, [loadMapThresholds]);

  // Map threshold validation and auto-save.
  const mapHigh = Number(mapThresholdHigh);
  const mapMedium = Number(mapThresholdMedium);
  const mapLow = Number(mapThresholdLow);

  const mapValidationError = useMemo<string | null>(() => {
    if (!mapThresholds) return null;
    if (isNaN(mapHigh) || isNaN(mapMedium) || isNaN(mapLow))
      return "All thresholds must be valid numbers.";
    if (mapHigh <= 0 || mapMedium <= 0 || mapLow <= 0)
      return "All thresholds must be positive integers.";
    if (!(mapHigh > mapMedium && mapMedium > mapLow))
      return "Thresholds must satisfy: high > medium > low.";
    return null;
  }, [mapHigh, mapMedium, mapLow, mapThresholds]);

  const [mapValidPayload, setMapValidPayload] = useState<MapColorThresholdsUpdate>({
    threshold_high: mapThresholds?.threshold_high ?? 0,
    threshold_medium: mapThresholds?.threshold_medium ?? 0,
    threshold_low: mapThresholds?.threshold_low ?? 0,
  });

  useEffect(() => {
    if (mapValidationError !== null || !mapThresholds) return;
    setMapValidPayload({
      threshold_high: mapHigh,
      threshold_medium: mapMedium,
      threshold_low: mapLow,
    });
  }, [mapHigh, mapMedium, mapLow, mapValidationError, mapThresholds]);

  const saveMapThresholds = useCallback(
    async (payload: MapColorThresholdsUpdate): Promise<void> => {
      await updateMapColorThresholds(payload);
    },
    [],
  );

  const { status: mapSaveStatus, errorText: mapSaveErrorText, retry: retryMapSave } =
    useAutoSave(mapValidPayload, saveMapThresholds);

  if (loading) {
    return (
      <Skeleton aria-label="Loading server settings…">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginBottom: 8 }}>
          <SkeletonItem size={32} />
          <SkeletonItem size={32} />
        </div>
        <SkeletonItem size={32} style={{ marginBottom: 8 }} />
        <SkeletonItem size={32} />
      </Skeleton>
    );
  }
  if (error)
    return (
      <MessageBar intent="error">
        <MessageBarBody>{error}</MessageBarBody>
      </MessageBar>
    );

  return (
    <div>
      {/* Service Health & Log Viewer section — shown first so users can
          immediately see whether fail2ban is reachable before editing settings. */}
      <ServerHealthSection />

      <div className={styles.sectionCard}>
        <div style={{ marginBottom: tokens.spacingVerticalS }}>
          <AutoSaveIndicator
            status={saveStatus}
            errorText={saveErrorText}
            onRetry={retrySave}
          />
        </div>
        <div className={styles.fieldRow}>
          <Field label="Log Level">
            <Select
              value={effectiveLogLevel}
              onChange={(_e, d) => {
                setLogLevel(d.value);
              }}
            >
              {LOG_LEVELS.map((l) => (
                <option key={l} value={l}>
                  {l}
                </option>
              ))}
            </Select>
          </Field>
          <Field label="Log Target">
            <Input
              value={effectiveLogTarget}
              placeholder="STDOUT / /var/log/fail2ban.log"
              onChange={(_e, d) => {
                setLogTarget(d.value);
              }}
            />
          </Field>
        </div>
        <div className={styles.fieldRow}>
          <Field label="DB Path">
            <Input
              readOnly
              value={settings?.db_path ?? ""}
              className={styles.codeFont}
            />
          </Field>
          <Field label="Syslog Socket">
            <Input
              readOnly
              value={settings?.syslog_socket ?? "(not configured)"}
              className={styles.codeFont}
            />
          </Field>
        </div>
        <div className={styles.fieldRow}>
          <Field
            label="DB Purge Age (s)"
            hint="Ban records older than this are removed from the fail2ban database."
          >
            <Input
              type="number"
              value={effectiveDbPurgeAge}
              onChange={(_e, d) => {
                setDbPurgeAge(d.value);
              }}
            />
          </Field>
          <Field
            label="DB Max Matches"
            hint="Maximum number of log-line matches stored per ban record."
          >
            <Input
              type="number"
              value={effectiveDbMaxMatches}
              onChange={(_e, d) => {
                setDbMaxMatches(d.value);
              }}
            />
          </Field>
        </div>
        <div className={styles.buttonRow}>
          <Button
            appearance="secondary"
            icon={<DocumentArrowDown24Regular />}
            disabled={flushing}
            onClick={() => void handleFlush()}
          >
            {flushing ? "Flushing…" : "Flush Logs"}
          </Button>
          <Button
            appearance="secondary"
            icon={<ArrowSync24Regular />}
            disabled={isReloading}
            onClick={() => void handleReload()}
          >
            {isReloading ? "Reloading…" : "Reload fail2ban"}
          </Button>
          <Button
            appearance="secondary"
            icon={<ArrowSync24Regular />}
            disabled={isRestarting}
            onClick={() => void handleRestart()}
          >
            {isRestarting ? "Restarting…" : "Restart fail2ban"}
          </Button>
        </div>
        {msg && (
          <MessageBar intent={msg.ok ? "success" : "error"}>
            <MessageBarBody>{msg.text}</MessageBarBody>
          </MessageBar>
        )}
      </div>

      {/* Map Color Thresholds section */}
      {mapLoadError ? (
        <div className={styles.sectionCard}>
          <MessageBar intent="error">
            <MessageBarBody>{mapLoadError}</MessageBarBody>
          </MessageBar>
        </div>
      ) : mapThresholds ? (
        <div className={styles.sectionCard}>
          <Text as="h3" size={500} weight="semibold" block>
            Map Color Thresholds
          </Text>
          <Text
            as="p"
            size={300}
            className={styles.infoText}
            block
            style={{ marginBottom: tokens.spacingVerticalM }}
          >
            Configure the ban count thresholds that determine country fill colors on
            the World Map. Countries with zero bans remain transparent. Colors
            smoothly interpolate between thresholds.
          </Text>

          <div style={{ marginBottom: tokens.spacingVerticalS }}>
            <AutoSaveIndicator
              status={mapValidationError ? "idle" : mapSaveStatus}
              errorText={mapSaveErrorText}
              onRetry={retryMapSave}
            />
          </div>

          {mapValidationError && (
            <MessageBar intent="error" style={{ marginBottom: tokens.spacingVerticalS }}>
              <MessageBarBody>{mapValidationError}</MessageBarBody>
            </MessageBar>
          )}

          <div className={styles.fieldRowThree}>
            <Field label="Low Threshold (Green)" required>
              <Input
                type="number"
                value={mapThresholdLow}
                onChange={(_, d) => {
                  setMapThresholdLow(d.value);
                }}
                min={1}
              />
            </Field>
            <Field label="Medium Threshold (Yellow)" required>
              <Input
                type="number"
                value={mapThresholdMedium}
                onChange={(_, d) => {
                  setMapThresholdMedium(d.value);
                }}
                min={1}
              />
            </Field>
            <Field label="High Threshold (Red)" required>
              <Input
                type="number"
                value={mapThresholdHigh}
                onChange={(_, d) => {
                  setMapThresholdHigh(d.value);
                }}
                min={1}
              />
            </Field>
          </div>

          <Text
            as="p"
            size={200}
            className={styles.infoText}
            style={{ marginTop: tokens.spacingVerticalS }}
          >
            • 1 to {mapThresholdLow}: Light green → Full green
            <br />• {mapThresholdLow} to {mapThresholdMedium}: Green → Yellow
            <br />• {mapThresholdMedium} to {mapThresholdHigh}: Yellow → Red
            <br />• {mapThresholdHigh}+: Solid red
          </Text>
        </div>
      ) : null}

    </div>
  );
}
