/**
 * HistoryPage — forensic exploration of all historical fail2ban ban records.
 *
 * Shows a paginated, filterable table of every ban ever recorded in the
 * fail2ban database.  Clicking an IP address opens a per-IP timeline view.
 * Rows with repeatedly-banned IPs are highlighted in amber.
 */

import { useEffect, useState } from "react";
import {
  Badge,
  Button,
  DataGrid,
  DataGridBody,
  DataGridCell,
  DataGridHeader,
  DataGridHeaderCell,
  DataGridRow,
  MessageBar,
  MessageBarBody,
  Spinner,
  Table,
  TableBody,
  TableCell,
  TableCellLayout,
  TableColumnDefinition,
  TableHeader,
  TableHeaderCell,
  TableRow,
  Text,
  Toolbar,
  ToolbarButton,
  createTableColumn,
  makeStyles,
  tokens,
} from "@fluentui/react-components";
import { useCardStyles } from "../theme/commonStyles";
import {
  ArrowCounterclockwiseRegular,
  ArrowLeftRegular,
  ChevronLeftRegular,
  ChevronRightRegular,
} from "@fluentui/react-icons";
import { DashboardFilterBar } from "../components/DashboardFilterBar";
import { useHistory, useIpHistory } from "../hooks/useHistory";
import type { HistoryBanItem, HistoryQuery, TimeRange } from "../types/history";
import type { BanOriginFilter } from "../types/ban";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

/** Ban counts at or above this threshold are highlighted. */
const HIGH_BAN_THRESHOLD = 5;

const PAGE_SIZE = 50;

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

const useStyles = makeStyles({
  root: {
    display: "flex",
    flexDirection: "column",
    gap: tokens.spacingVerticalL,
    padding: tokens.spacingVerticalXXL,
    paddingLeft: tokens.spacingHorizontalXXL,
    paddingRight: tokens.spacingHorizontalXXL,
  },
  header: {
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    flexWrap: "wrap",
    gap: tokens.spacingHorizontalM,
  },
  filterRow: {
    display: "flex",
    alignItems: "flex-end",
    gap: tokens.spacingHorizontalM,
    flexWrap: "wrap",
  },
  tableWrapper: {
    overflow: "auto",
    borderRadius: tokens.borderRadiusMedium,
    border: `1px solid ${tokens.colorNeutralStroke1}`,
  },
  ipCell: {
    fontFamily: "Consolas, 'Courier New', monospace",
    fontSize: "0.85rem",
    color: tokens.colorBrandForeground1,
    cursor: "pointer",
    textDecoration: "underline",
  },
  highBanRow: {
    backgroundColor: tokens.colorPaletteYellowBackground1,
  },
  pagination: {
    display: "flex",
    alignItems: "center",
    gap: tokens.spacingHorizontalM,
    justifyContent: "flex-end",
  },
  detailGrid: {
    display: "grid",
    gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))",
    gap: tokens.spacingVerticalM,
    padding: tokens.spacingVerticalM,
    marginBottom: tokens.spacingVerticalM,
  },
  detailField: {
    display: "flex",
    flexDirection: "column",
    gap: tokens.spacingVerticalXS,
  },
  detailLabel: {
    color: tokens.colorNeutralForeground3,
    fontSize: "0.75rem",
    textTransform: "uppercase",
    letterSpacing: "0.05em",
  },
  detailValue: {
    fontSize: "0.9rem",
    fontWeight: "600",
  },
  monoText: {
    fontFamily: "Consolas, 'Courier New', monospace",
    fontSize: "0.85rem",
  },
});

// ---------------------------------------------------------------------------
// Utilities
// ---------------------------------------------------------------------------

function areHistoryQueriesEqual(
  a: HistoryQuery,
  b: HistoryQuery,
): boolean {
  return (
    a.range === b.range &&
    a.origin === b.origin &&
    a.jail === b.jail &&
    a.ip === b.ip &&
    a.source === b.source &&
    a.page === b.page &&
    a.page_size === b.page_size
  );
}

// ---------------------------------------------------------------------------
// Column definitions for the main history table
// ---------------------------------------------------------------------------

const HISTORY_COLUMNS = (
  onClickIp: (ip: string) => void,
  styles: ReturnType<typeof useStyles>,
): TableColumnDefinition<HistoryBanItem>[] =>
  [
    createTableColumn<HistoryBanItem>({
      columnId: "banned_at",
      renderHeaderCell: () => "Banned At",
      renderCell: (item) => (
        <Text size={200}>{new Date(item.banned_at).toLocaleString()}</Text>
      ),
    }),
    createTableColumn<HistoryBanItem>({
      columnId: "ip",
      renderHeaderCell: () => "IP Address",
      renderCell: (item) => (
        <span
          className={styles.ipCell}
          role="button"
          tabIndex={0}
          onClick={(): void => {
            onClickIp(item.ip);
          }}
          onKeyDown={(e): void => {
            if (e.key === "Enter" || e.key === " ") onClickIp(item.ip);
          }}
        >
          {item.ip}
        </span>
      ),
    }),
    createTableColumn<HistoryBanItem>({
      columnId: "jail",
      renderHeaderCell: () => "Jail",
      renderCell: (item) => <Text size={200}>{item.jail}</Text>,
    }),
    createTableColumn<HistoryBanItem>({
      columnId: "country",
      renderHeaderCell: () => "Country",
      renderCell: (item) => (
        <Text size={200}>{item.country_name ?? item.country_code ?? "—"}</Text>
      ),
    }),
    createTableColumn<HistoryBanItem>({
      columnId: "failures",
      renderHeaderCell: () => "Failures",
      renderCell: (item) => <Text size={200}>{String(item.failures)}</Text>,
    }),
    createTableColumn<HistoryBanItem>({
      columnId: "ban_count",
      renderHeaderCell: () => "Times Banned",
      renderCell: (item) => (
        <Badge
          appearance="filled"
          color={item.ban_count >= HIGH_BAN_THRESHOLD ? "danger" : "subtle"}
          size="medium"
        >
          {String(item.ban_count)}
        </Badge>
      ),
    }),
  ] as ReturnType<typeof createTableColumn<HistoryBanItem>>[];

// ---------------------------------------------------------------------------
// IpDetailView — per-IP detail view
// ---------------------------------------------------------------------------

interface IpDetailViewProps {
  ip: string;
  onBack: () => void;
}

function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Element {
  const styles = useStyles();
  const cardStyles = useCardStyles();
  const { detail, loading, error, refresh } = useIpHistory(ip);

  if (loading) {
    return (
      <div
        style={{ display: "flex", justifyContent: "center", padding: tokens.spacingVerticalXL }}
      >
        <Spinner label={`Loading history for ${ip}…`} />
      </div>
    );
  }

  if (error) {
    return (
      <MessageBar intent="error">
        <MessageBarBody>{error}</MessageBarBody>
      </MessageBar>
    );
  }

  if (!detail) {
    return (
      <MessageBar intent="warning">
        <MessageBarBody>No history found for {ip}.</MessageBarBody>
      </MessageBar>
    );
  }

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: tokens.spacingVerticalL }}>
      {/* Back button + heading */}
      <div className={styles.header}>
        <div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalM }}>
          <Button
            icon={<ArrowLeftRegular />}
            appearance="subtle"
            onClick={onBack}
          >
            Back to list
          </Button>
          <Text as="h2" size={600} weight="semibold" className={styles.monoText}>
            {ip}
          </Text>
        </div>
        <Button
          icon={<ArrowCounterclockwiseRegular />}
          appearance="subtle"
          onClick={(): void => {
            refresh();
          }}
        >
          Refresh
        </Button>
      </div>

      {/* Summary grid */}
      <div className={`${cardStyles.card} ${styles.detailGrid}`}>
        <div className={styles.detailField}>
          <span className={styles.detailLabel}>Total Bans</span>
          <span className={styles.detailValue}>{String(detail.total_bans)}</span>
        </div>
        <div className={styles.detailField}>
          <span className={styles.detailLabel}>Total Failures</span>
          <span className={styles.detailValue}>{String(detail.total_failures)}</span>
        </div>
        <div className={styles.detailField}>
          <span className={styles.detailLabel}>Last Banned</span>
          <span className={styles.detailValue}>
            {detail.last_ban_at
              ? new Date(detail.last_ban_at).toLocaleString()
              : "—"}
          </span>
        </div>
        <div className={styles.detailField}>
          <span className={styles.detailLabel}>Country</span>
          <span className={styles.detailValue}>
            {detail.country_name ?? detail.country_code ?? "—"}
          </span>
        </div>
        <div className={styles.detailField}>
          <span className={styles.detailLabel}>ASN</span>
          <span className={styles.detailValue}>{detail.asn ?? "—"}</span>
        </div>
        <div className={styles.detailField}>
          <span className={styles.detailLabel}>Organisation</span>
          <span className={styles.detailValue}>{detail.org ?? "—"}</span>
        </div>
      </div>

      {/* Timeline table */}
      <Text weight="semibold" size={400}>
        Ban Timeline ({String(detail.timeline.length)} events)
      </Text>

      <div className={styles.tableWrapper}>
        <Table size="small" aria-label="Ban timeline">
          <TableHeader>
            <TableRow>
              <TableHeaderCell>Banned At</TableHeaderCell>
              <TableHeaderCell>Jail</TableHeaderCell>
              <TableHeaderCell>Failures</TableHeaderCell>
              <TableHeaderCell>Times Banned</TableHeaderCell>
              <TableHeaderCell>Matched Lines</TableHeaderCell>
            </TableRow>
          </TableHeader>
          <TableBody>
            {detail.timeline.map((event) => (
              <TableRow key={`${event.jail}-${event.banned_at}`}>
                <TableCell>
                  <TableCellLayout>
                    {new Date(event.banned_at).toLocaleString()}
                  </TableCellLayout>
                </TableCell>
                <TableCell>
                  <TableCellLayout>{event.jail}</TableCellLayout>
                </TableCell>
                <TableCell>
                  <TableCellLayout>{String(event.failures)}</TableCellLayout>
                </TableCell>
                <TableCell>
                  <TableCellLayout>{String(event.ban_count)}</TableCellLayout>
                </TableCell>
                <TableCell>
                  <TableCellLayout>
                    {event.matches.length === 0 ? (
                      <Text size={200} style={{ color: tokens.colorNeutralForeground3 }}>
                        —
                      </Text>
                    ) : (
                      <Text
                        size={100}
                        style={{
                          fontFamily: "Consolas, 'Courier New', monospace",
                          whiteSpace: "pre-wrap",
                          wordBreak: "break-all",
                        }}
                      >
                        {event.matches.join("\n")}
                      </Text>
                    )}
                  </TableCellLayout>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// HistoryPage — main component
// ---------------------------------------------------------------------------

export function HistoryPage(): React.JSX.Element {
  const styles = useStyles();

  // Filter state
  const [range, setRange] = useState<TimeRange>("7d");
  const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all");
  const [jailFilter, setJailFilter] = useState("");
  const [ipFilter, setIpFilter] = useState("");
  const [appliedQuery, setAppliedQuery] = useState<HistoryQuery>({
    source: "archive",
    page_size: PAGE_SIZE,
  });

  // Per-IP detail navigation
  const [selectedIp, setSelectedIp] = useState<string | null>(null);

  const { items, total, page, loading, error, setPage, refresh } =
    useHistory(appliedQuery);

  useEffect((): void => {
    const nextQuery: HistoryQuery = {
      range,
      origin: originFilter !== "all" ? originFilter : undefined,
      jail: jailFilter.trim() || undefined,
      ip: ipFilter.trim() || undefined,
      source: "archive",
      page: 1,
      page_size: PAGE_SIZE,
    };

    if (areHistoryQueriesEqual(nextQuery, appliedQuery)) {
      return;
    }

    setPage(1);
    setAppliedQuery(nextQuery);
  }, [range, originFilter, jailFilter, ipFilter, setPage, appliedQuery]);

  const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));

  /** History table columns with IP click handler. */
  const columns = HISTORY_COLUMNS(
    (ip: string): void => {
      setSelectedIp(ip);
    },
    styles,
  );

  // If an IP is selected, show the detail view.
  if (selectedIp !== null) {
    return (
      <div className={styles.root}>
        <IpDetailView
          ip={selectedIp}
          onBack={(): void => {
            setSelectedIp(null);
          }}
        />
      </div>
    );
  }

  return (
    <div className={styles.root}>
      {/* ---------------------------------------------------------------- */}
      {/* Header                                                            */}
      {/* ---------------------------------------------------------------- */}
      <div className={styles.header}>
        <Text as="h1" size={700} weight="semibold">
          History
        </Text>
        <Toolbar size="small">
          <ToolbarButton
            icon={<ArrowCounterclockwiseRegular />}
            onClick={(): void => {
              refresh();
            }}
            disabled={loading}
            title="Refresh"
          />
        </Toolbar>
      </div>

      {/* ---------------------------------------------------------------- */}
      {/* Filter bar                                                        */}
      {/* ---------------------------------------------------------------- */}
      <div className={styles.filterRow}>
        <DashboardFilterBar
          timeRange={range}
          onTimeRangeChange={(value) => {
            setRange(value);
          }}
          originFilter={originFilter}
          onOriginFilterChange={(value) => {
            setOriginFilter(value);
          }}
          jail={jailFilter}
          onJailChange={(value) => {
            setJailFilter(value);
          }}
          ip={ipFilter}
          onIpChange={(value) => {
            setIpFilter(value);
          }}
        />


      {/* ---------------------------------------------------------------- */}
      {/* Summary                                                           */}
      {/* ---------------------------------------------------------------- */}
      {!loading && !error && (
        <Text size={300} style={{ color: tokens.colorNeutralForeground3 }}>
          {String(total)} record{total !== 1 ? "s" : ""} found ·
          Page {String(page)} of {String(totalPages)} ·
          Rows highlighted in yellow have {String(HIGH_BAN_THRESHOLD)}+ repeat bans
        </Text>
      )}

      {/* ---------------------------------------------------------------- */}
      {/* DataGrid table                                                    */}
      {/* ---------------------------------------------------------------- */}
      {!loading && !error && (
        <div className={styles.tableWrapper}>
          <DataGrid
            items={items}
            columns={columns}
            getRowId={(item: HistoryBanItem) => `${item.ip}-${item.banned_at}`}
            focusMode="composite"
          >
            <DataGridHeader>
              <DataGridRow>
                {({ renderHeaderCell }) => (
                  <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
                )}
              </DataGridRow>
            </DataGridHeader>
            <DataGridBody<HistoryBanItem>>
              {({ item }) => (
                <DataGridRow<HistoryBanItem>
                  key={`${item.ip}-${item.banned_at}`}
                  className={
                    item.ban_count >= HIGH_BAN_THRESHOLD
                      ? styles.highBanRow
                      : undefined
                  }
                >
                  {({ renderCell }) => (
                    <DataGridCell>{renderCell(item)}</DataGridCell>
                  )}
                </DataGridRow>
              )}
            </DataGridBody>
          </DataGrid>
        </div>
      )}

      {/* ---------------------------------------------------------------- */}
      {/* Pagination                                                        */}
      {/* ---------------------------------------------------------------- */}
      {!loading && !error && totalPages > 1 && (
        <div className={styles.pagination}>
          <Button
            icon={<ChevronLeftRegular />}
            appearance="subtle"
            size="small"
            disabled={page <= 1}
            onClick={(): void => {
              setPage(page - 1);
            }}
          />
          <Text size={200}>
            Page {String(page)} / {String(totalPages)}
          </Text>
          <Button
            icon={<ChevronRightRegular />}
            appearance="subtle"
            size="small"
            disabled={page >= totalPages}
            onClick={(): void => {
              setPage(page + 1);
            }}
          />
        </div>
      )}
    </div>
  );
}
