/**
 * Jails management page.
 *
 * Provides three sections in a vertically-stacked layout:
 * 1. **Jail Overview** — table of all jails with quick status badges and
 *    per-row start/stop/idle/reload controls.
 * 2. **Ban / Unban IP** — form to manually ban or unban an IP address.
 * 3. **IP Lookup** — check whether an IP is currently banned and view its
 *    geo-location details.
 */

import { useState } from "react";
import {
  Badge,
  Button,
  DataGrid,
  DataGridBody,
  DataGridCell,
  DataGridHeader,
  DataGridHeaderCell,
  DataGridRow,
  Field,
  Input,
  MessageBar,
  MessageBarBody,
  Select,
  Spinner,
  Text,
  Tooltip,
  makeStyles,
  tokens,
  type TableColumnDefinition,
  createTableColumn,
} from "@fluentui/react-components";
import {
  ArrowClockwiseRegular,
  ArrowSyncRegular,
  LockClosedRegular,
  LockOpenRegular,
  PauseRegular,
  PlayRegular,
  SearchRegular,
  StopRegular,
} from "@fluentui/react-icons";
import { Link } from "react-router-dom";
import { useActiveBans, useIpLookup, useJails } from "../hooks/useJails";
import type { JailSummary } from "../types/jail";
import { ApiError } from "../api/client";

// ---------------------------------------------------------------------------
// Styles
// ---------------------------------------------------------------------------

const useStyles = makeStyles({
  root: {
    display: "flex",
    flexDirection: "column",
    gap: tokens.spacingVerticalL,
  },
  section: {
    display: "flex",
    flexDirection: "column",
    gap: tokens.spacingVerticalS,
    backgroundColor: tokens.colorNeutralBackground1,
    borderRadius: tokens.borderRadiusMedium,
    borderTopWidth: "1px",
    borderTopStyle: "solid",
    borderTopColor: tokens.colorNeutralStroke2,
    borderRightWidth: "1px",
    borderRightStyle: "solid",
    borderRightColor: tokens.colorNeutralStroke2,
    borderBottomWidth: "1px",
    borderBottomStyle: "solid",
    borderBottomColor: tokens.colorNeutralStroke2,
    borderLeftWidth: "1px",
    borderLeftStyle: "solid",
    borderLeftColor: tokens.colorNeutralStroke2,
    padding: tokens.spacingVerticalM,
  },
  sectionHeader: {
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    gap: tokens.spacingHorizontalM,
    paddingBottom: tokens.spacingVerticalS,
    borderBottomWidth: "1px",
    borderBottomStyle: "solid",
    borderBottomColor: tokens.colorNeutralStroke2,
  },
  tableWrapper: { overflowX: "auto" },
  centred: {
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    padding: tokens.spacingVerticalXXL,
  },
  mono: {
    fontFamily: "Consolas, 'Courier New', monospace",
    fontSize: tokens.fontSizeBase200,
  },
  formRow: {
    display: "flex",
    flexWrap: "wrap",
    gap: tokens.spacingHorizontalM,
    alignItems: "flex-end",
  },
  formField: { minWidth: "180px", flexGrow: 1 },
  actionRow: {
    display: "flex",
    flexWrap: "wrap",
    gap: tokens.spacingHorizontalS,
  },
  lookupResult: {
    display: "flex",
    flexDirection: "column",
    gap: tokens.spacingVerticalS,
    marginTop: tokens.spacingVerticalS,
    padding: tokens.spacingVerticalS,
    backgroundColor: tokens.colorNeutralBackground2,
    borderRadius: tokens.borderRadiusMedium,
    borderTopWidth: "1px",
    borderTopStyle: "solid",
    borderTopColor: tokens.colorNeutralStroke2,
    borderRightWidth: "1px",
    borderRightStyle: "solid",
    borderRightColor: tokens.colorNeutralStroke2,
    borderBottomWidth: "1px",
    borderBottomStyle: "solid",
    borderBottomColor: tokens.colorNeutralStroke2,
    borderLeftWidth: "1px",
    borderLeftStyle: "solid",
    borderLeftColor: tokens.colorNeutralStroke2,
  },
  lookupRow: {
    display: "flex",
    gap: tokens.spacingHorizontalM,
    flexWrap: "wrap",
    alignItems: "center",
  },
  lookupLabel: { fontWeight: tokens.fontWeightSemibold },
});

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function fmtSeconds(s: number): string {
  if (s < 0) return "permanent";
  if (s < 60) return `${String(s)}s`;
  if (s < 3600) return `${String(Math.round(s / 60))}m`;
  return `${String(Math.round(s / 3600))}h`;
}

// ---------------------------------------------------------------------------
// Jail overview columns
// ---------------------------------------------------------------------------

const jailColumns: TableColumnDefinition<JailSummary>[] = [
  createTableColumn<JailSummary>({
    columnId: "name",
    renderHeaderCell: () => "Jail",
    renderCell: (j) => (
      <Link to={`/jails/${encodeURIComponent(j.name)}`} style={{ textDecoration: "none" }}>
        <Text style={{ fontFamily: "Consolas, 'Courier New', monospace", fontSize: "0.85rem" }}>
          {j.name}
        </Text>
      </Link>
    ),
  }),
  createTableColumn<JailSummary>({
    columnId: "status",
    renderHeaderCell: () => "Status",
    renderCell: (j) => {
      if (!j.running) return <Badge appearance="filled" color="danger">stopped</Badge>;
      if (j.idle) return <Badge appearance="filled" color="warning">idle</Badge>;
      return <Badge appearance="filled" color="success">running</Badge>;
    },
  }),
  createTableColumn<JailSummary>({
    columnId: "backend",
    renderHeaderCell: () => "Backend",
    renderCell: (j) => <Text size={200}>{j.backend}</Text>,
  }),
  createTableColumn<JailSummary>({
    columnId: "banned",
    renderHeaderCell: () => "Banned",
    renderCell: (j) => (
      <Text size={200}>{j.status ? String(j.status.currently_banned) : "—"}</Text>
    ),
  }),
  createTableColumn<JailSummary>({
    columnId: "failed",
    renderHeaderCell: () => "Failed",
    renderCell: (j) => (
      <Text size={200}>{j.status ? String(j.status.currently_failed) : "—"}</Text>
    ),
  }),
  createTableColumn<JailSummary>({
    columnId: "findTime",
    renderHeaderCell: () => "Find Time",
    renderCell: (j) => <Text size={200}>{fmtSeconds(j.find_time)}</Text>,
  }),
  createTableColumn<JailSummary>({
    columnId: "banTime",
    renderHeaderCell: () => "Ban Time",
    renderCell: (j) => <Text size={200}>{fmtSeconds(j.ban_time)}</Text>,
  }),
  createTableColumn<JailSummary>({
    columnId: "maxRetry",
    renderHeaderCell: () => "Max Retry",
    renderCell: (j) => <Text size={200}>{String(j.max_retry)}</Text>,
  }),
];

// ---------------------------------------------------------------------------
// Sub-component: Jail overview section
// ---------------------------------------------------------------------------

function JailOverviewSection(): React.JSX.Element {
  const styles = useStyles();
  const { jails, total, loading, error, refresh, startJail, stopJail, setIdle, reloadJail, reloadAll } =
    useJails();
  const [opError, setOpError] = useState<string | null>(null);

  const handle = (fn: () => Promise<void>): void => {
    setOpError(null);
    fn().catch((err: unknown) => {
      setOpError(err instanceof Error ? err.message : String(err));
    });
  };

  return (
    <div className={styles.section}>
      <div className={styles.sectionHeader}>
        <Text as="h2" size={500} weight="semibold">
          Jail Overview
          {total > 0 && (
            <Badge appearance="tint" style={{ marginLeft: "8px" }}>
              {String(total)}
            </Badge>
          )}
        </Text>
        <div className={styles.actionRow}>
          <Button
            size="small"
            appearance="subtle"
            icon={<ArrowSyncRegular />}
            onClick={() => { handle(reloadAll); }}
          >
            Reload All
          </Button>
          <Button size="small" appearance="subtle" icon={<ArrowClockwiseRegular />} onClick={refresh}>
            Refresh
          </Button>
        </div>
      </div>

      {opError && (
        <MessageBar intent="error">
          <MessageBarBody>{opError}</MessageBarBody>
        </MessageBar>
      )}
      {error && (
        <MessageBar intent="error">
          <MessageBarBody>Failed to load jails: {error}</MessageBarBody>
        </MessageBar>
      )}

      {loading && jails.length === 0 ? (
        <div className={styles.centred}>
          <Spinner label="Loading jails…" />
        </div>
      ) : (
        <div className={styles.tableWrapper}>
          <DataGrid
            items={jails}
            columns={jailColumns}
            getRowId={(j: JailSummary) => j.name}
            focusMode="composite"
          >
            <DataGridHeader>
              <DataGridRow>
                {({ renderHeaderCell }) => (
                  <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
                )}
              </DataGridRow>
            </DataGridHeader>
            <DataGridBody<JailSummary>>
              {({ item }) => (
                <DataGridRow<JailSummary> key={item.name}>
                  {({ renderCell, columnId }) => {
                    if (columnId === "status") {
                      return (
                        <DataGridCell>
                          <div style={{ display: "flex", gap: "6px", alignItems: "center" }}>
                            {renderCell(item)}
                            <Tooltip
                              content={item.running ? "Stop jail" : "Start jail"}
                              relationship="label"
                            >
                              <Button
                                size="small"
                                appearance="subtle"
                                icon={item.running ? <StopRegular /> : <PlayRegular />}
                                onClick={() => {
                                  handle(async () => {
                                    if (item.running) await stopJail(item.name);
                                    else await startJail(item.name);
                                  });
                                }}
                                aria-label={
                                  item.running ? `Stop ${item.name}` : `Start ${item.name}`
                                }
                              />
                            </Tooltip>
                            <Tooltip
                              content={item.idle ? "Resume from idle" : "Set idle"}
                              relationship="label"
                            >
                              <Button
                                size="small"
                                appearance="subtle"
                                icon={<PauseRegular />}
                                onClick={() => {
                                  handle(async () => setIdle(item.name, !item.idle));
                                }}
                                disabled={!item.running}
                                aria-label={`Toggle idle for ${item.name}`}
                              />
                            </Tooltip>
                            <Tooltip content="Reload jail" relationship="label">
                              <Button
                                size="small"
                                appearance="subtle"
                                icon={<ArrowSyncRegular />}
                                onClick={() => {
                                  handle(async () => reloadJail(item.name));
                                }}
                                aria-label={`Reload ${item.name}`}
                              />
                            </Tooltip>
                          </div>
                        </DataGridCell>
                      );
                    }
                    return <DataGridCell>{renderCell(item)}</DataGridCell>;
                  }}
                </DataGridRow>
              )}
            </DataGridBody>
          </DataGrid>
        </div>
      )}

    </div>
  );
}

// ---------------------------------------------------------------------------
// Sub-component: Ban / Unban IP form
// ---------------------------------------------------------------------------

interface BanUnbanFormProps {
  jailNames: string[];
  onBan: (jail: string, ip: string) => Promise<void>;
  onUnban: (ip: string, jail?: string) => Promise<void>;
}

function BanUnbanForm({ jailNames, onBan, onUnban }: BanUnbanFormProps): React.JSX.Element {
  const styles = useStyles();
  const [banIpVal, setBanIpVal] = useState("");
  const [banJail, setBanJail] = useState("");
  const [unbanIpVal, setUnbanIpVal] = useState("");
  const [unbanJail, setUnbanJail] = useState("");
  const [formError, setFormError] = useState<string | null>(null);
  const [formSuccess, setFormSuccess] = useState<string | null>(null);

  const handleBan = (): void => {
    setFormError(null);
    setFormSuccess(null);
    if (!banIpVal.trim() || !banJail) {
      setFormError("Both IP address and jail are required.");
      return;
    }
    onBan(banJail, banIpVal.trim())
      .then(() => {
        setFormSuccess(`${banIpVal.trim()} banned in ${banJail}.`);
        setBanIpVal("");
      })
      .catch((err: unknown) => {
        const msg =
          err instanceof ApiError
            ? `${String(err.status)}: ${err.body}`
            : err instanceof Error
              ? err.message
              : String(err);
        setFormError(msg);
      });
  };

  const handleUnban = (fromAllJails: boolean): void => {
    setFormError(null);
    setFormSuccess(null);
    if (!unbanIpVal.trim()) {
      setFormError("IP address is required.");
      return;
    }
    const jail = fromAllJails ? undefined : unbanJail || undefined;
    onUnban(unbanIpVal.trim(), jail)
      .then(() => {
        const scope = jail ?? "all jails";
        setFormSuccess(`${unbanIpVal.trim()} unbanned from ${scope}.`);
        setUnbanIpVal("");
        setUnbanJail("");
      })
      .catch((err: unknown) => {
        const msg =
          err instanceof ApiError
            ? `${String(err.status)}: ${err.body}`
            : err instanceof Error
              ? err.message
              : String(err);
        setFormError(msg);
      });
  };

  return (
    <div className={styles.section}>
      <div className={styles.sectionHeader}>
        <Text as="h2" size={500} weight="semibold">
          Ban / Unban IP
        </Text>
      </div>

      {formError && (
        <MessageBar intent="error">
          <MessageBarBody>{formError}</MessageBarBody>
        </MessageBar>
      )}
      {formSuccess && (
        <MessageBar intent="success">
          <MessageBarBody>{formSuccess}</MessageBarBody>
        </MessageBar>
      )}

      {/* Ban row */}
      <Text size={300} weight="semibold">
        Ban an IP
      </Text>
      <div className={styles.formRow}>
        <div className={styles.formField}>
          <Field label="IP Address">
            <Input
              placeholder="e.g. 192.168.1.100"
              value={banIpVal}
              onChange={(_, d) => {
                setBanIpVal(d.value);
              }}
            />
          </Field>
        </div>
        <div className={styles.formField}>
          <Field label="Jail">
            <Select
              value={banJail}
              onChange={(_, d) => {
                setBanJail(d.value);
              }}
            >
              <option value="">Select jail…</option>
              {jailNames.map((n) => (
                <option key={n} value={n}>
                  {n}
                </option>
              ))}
            </Select>
          </Field>
        </div>
        <Button
          appearance="primary"
          icon={<LockClosedRegular />}
          onClick={handleBan}
          style={{ marginBottom: "4px" }}
        >
          Ban
        </Button>
      </div>

      {/* Unban row */}
      <Text
        size={300}
        weight="semibold"
        style={{ marginTop: tokens.spacingVerticalS }}
      >
        Unban an IP
      </Text>
      <div className={styles.formRow}>
        <div className={styles.formField}>
          <Field label="IP Address">
            <Input
              placeholder="e.g. 192.168.1.100"
              value={unbanIpVal}
              onChange={(_, d) => {
                setUnbanIpVal(d.value);
              }}
            />
          </Field>
        </div>
        <div className={styles.formField}>
          <Field label="Jail (optional — leave blank for all)">
            <Select
              value={unbanJail}
              onChange={(_, d) => {
                setUnbanJail(d.value);
              }}
            >
              <option value="">All jails</option>
              {jailNames.map((n) => (
                <option key={n} value={n}>
                  {n}
                </option>
              ))}
            </Select>
          </Field>
        </div>
        <Button
          appearance="secondary"
          icon={<LockOpenRegular />}
          onClick={() => {
            handleUnban(false);
          }}
          style={{ marginBottom: "4px" }}
        >
          Unban
        </Button>
        <Button
          appearance="outline"
          icon={<LockOpenRegular />}
          onClick={() => {
            handleUnban(true);
          }}
          style={{ marginBottom: "4px" }}
        >
          Unban from All Jails
        </Button>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Sub-component: IP Lookup section
// ---------------------------------------------------------------------------

function IpLookupSection(): React.JSX.Element {
  const styles = useStyles();
  const { result, loading, error, lookup, clear } = useIpLookup();
  const [inputVal, setInputVal] = useState("");

  const handleLookup = (): void => {
    if (inputVal.trim()) {
      lookup(inputVal.trim());
    }
  };

  return (
    <div className={styles.section}>
      <div className={styles.sectionHeader}>
        <Text as="h2" size={500} weight="semibold">
          IP Lookup
        </Text>
      </div>

      <div className={styles.formRow}>
        <div className={styles.formField}>
          <Field label="IP Address">
            <Input
              placeholder="e.g. 1.2.3.4 or 2001:db8::1"
              value={inputVal}
              onChange={(_, d) => {
                setInputVal(d.value);
                clear();
              }}
              onKeyDown={(e) => {
                if (e.key === "Enter") handleLookup();
              }}
            />
          </Field>
        </div>
        <Button
          appearance="primary"
          icon={loading ? <Spinner size="tiny" /> : <SearchRegular />}
          onClick={handleLookup}
          disabled={loading || !inputVal.trim()}
          style={{ marginBottom: "4px" }}
        >
          Look up
        </Button>
      </div>

      {error && (
        <MessageBar intent="error">
          <MessageBarBody>{error}</MessageBarBody>
        </MessageBar>
      )}

      {result && (
        <div className={styles.lookupResult}>
          <div className={styles.lookupRow}>
            <Text className={styles.lookupLabel}>IP:</Text>
            <Text className={styles.mono}>{result.ip}</Text>
          </div>

          <div className={styles.lookupRow}>
            <Text className={styles.lookupLabel}>Currently banned in:</Text>
            {result.currently_banned_in.length === 0 ? (
              <Badge appearance="tint" color="success">
                not banned
              </Badge>
            ) : (
              <div style={{ display: "flex", flexWrap: "wrap", gap: "4px" }}>
                {result.currently_banned_in.map((j) => (
                  <Badge key={j} appearance="filled" color="danger">
                    {j}
                  </Badge>
                ))}
              </div>
            )}
          </div>

          {result.geo && (
            <>
              {result.geo.country_name && (
                <div className={styles.lookupRow}>
                  <Text className={styles.lookupLabel}>Country:</Text>
                  <Text>
                    {result.geo.country_name}
                    {result.geo.country_code ? ` (${result.geo.country_code})` : ""}
                  </Text>
                </div>
              )}
              {result.geo.org && (
                <div className={styles.lookupRow}>
                  <Text className={styles.lookupLabel}>Organisation:</Text>
                  <Text>{result.geo.org}</Text>
                </div>
              )}
              {result.geo.asn && (
                <div className={styles.lookupRow}>
                  <Text className={styles.lookupLabel}>ASN:</Text>
                  <Text className={styles.mono}>{result.geo.asn}</Text>
                </div>
              )}
            </>
          )}
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Page component
// ---------------------------------------------------------------------------

/**
 * Jails management page.
 *
 * Renders three sections: Jail Overview, Ban/Unban IP, and IP Lookup.
 */
export function JailsPage(): React.JSX.Element {
  const styles = useStyles();
  const { jails } = useJails();
  const { banIp, unbanIp } = useActiveBans();

  const jailNames = jails.map((j) => j.name);

  return (
    <div className={styles.root}>
      <Text as="h1" size={700} weight="semibold">
        Jails
      </Text>

      <JailOverviewSection />

      <BanUnbanForm jailNames={jailNames} onBan={banIp} onUnban={unbanIp} />

      <IpLookupSection />
    </div>
  );
}
