/**
 * `BannedIpsSection` component.
 *
 * Displays a paginated table of IPs currently banned in a specific fail2ban
 * jail.  Supports server-side search filtering (debounced), page navigation,
 * page-size selection, and per-row unban actions.
 *
 * Only the current page is geo-enriched by the backend, so the component
 * remains fast even when a jail contains thousands of banned IPs.
 */

import { useMemo } from "react";
import {
  Badge,
  Button,
  DataGrid,
  DataGridBody,
  DataGridCell,
  DataGridHeader,
  DataGridHeaderCell,
  DataGridRow,
  Dropdown,
  Field,
  Input,
  MessageBar,
  MessageBarBody,
  Option,
  Spinner,
  Text,
  Tooltip,
  makeStyles,
  tokens,
  type TableColumnDefinition,
  createTableColumn,
} from "@fluentui/react-components";
import { useCommonSectionStyles } from "../../components/commonStyles";
import { formatTimestamp } from "../../utils/formatDate";
import {
  ArrowClockwiseRegular,
  ChevronLeftRegular,
  ChevronRightRegular,
  DismissRegular,
  SearchRegular,
} from "@fluentui/react-icons";
import type { ActiveBan } from "../../types/jail";

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

/** Available page-size options. */
const PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const;

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

const useStyles = makeStyles({
  header: {
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    gap: tokens.spacingHorizontalM,
    paddingBottom: tokens.spacingVerticalS,
    borderBottomWidth: "1px",
    borderBottomStyle: "solid",
    borderBottomColor: tokens.colorNeutralStroke2,
  },
  headerLeft: {
    display: "flex",
    alignItems: "center",
    gap: tokens.spacingHorizontalM,
  },
  toolbar: {
    display: "flex",
    alignItems: "flex-end",
    gap: tokens.spacingHorizontalS,
    flexWrap: "wrap",
  },
  searchField: {
    minWidth: "200px",
    flexGrow: 1,
  },
  tableWrapper: {
    overflowX: "auto",
  },
  centred: {
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    padding: tokens.spacingVerticalXXL,
  },
  pagination: {
    display: "flex",
    alignItems: "center",
    justifyContent: "flex-end",
    gap: tokens.spacingHorizontalS,
    paddingTop: tokens.spacingVerticalS,
    flexWrap: "wrap",
  },
  pageSizeWrapper: {
    display: "flex",
    alignItems: "center",
    gap: tokens.spacingHorizontalXS,
  },
  rowsPerPageDropdown: {
    minWidth: "80px",
  },
  mono: {
    fontFamily: tokens.fontFamilyMonospace,
    fontSize: tokens.fontSizeBase200,
  },
  emptyText: {
    color: tokens.colorNeutralForeground3,
  },
  emptyValue: {
    color: tokens.colorNeutralForeground4,
  },
});

// ---------------------------------------------------------------------------
// Column definitions
// ---------------------------------------------------------------------------

/** A row item augmented with an `onUnban` callback for the row action. */
interface BanRow {
  ban: ActiveBan;
  onUnban: (ip: string) => Promise<void>;
}

// ---------------------------------------------------------------------------
// Props
// ---------------------------------------------------------------------------

/** Props for {@link BannedIpsSection}. */
export interface BannedIpsSectionProps {
  items: ActiveBan[];
  total: number;
  page: number;
  pageSize: number;
  search: string;
  loading: boolean;
  error: string | null;
  opError: string | null;
  onSearch: (term: string) => void;
  onPageChange: (page: number) => void;
  onPageSizeChange: (size: number) => void;
  onRefresh: () => Promise<void>;
  onUnban: (ip: string) => Promise<void>;
}

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

/**
 * Paginated section showing currently banned IPs for a single jail.
 *
 * @param props - {@link BannedIpsSectionProps}
 */
export function BannedIpsSection({
  items,
  total,
  page,
  pageSize,
  search,
  loading,
  error,
  opError,
  onSearch,
  onPageChange,
  onPageSizeChange,
  onRefresh,
  onUnban,
}: BannedIpsSectionProps): React.JSX.Element {
  const styles = useStyles();
  const sectionStyles = useCommonSectionStyles();

  const columns: TableColumnDefinition<BanRow>[] = useMemo(
    () => [
      createTableColumn<BanRow>({
        columnId: "ip",
        renderHeaderCell: () => "IP Address",
        renderCell: ({ ban }) => <Text className={styles.mono}>{ban.ip}</Text>,
      }),
      createTableColumn<BanRow>({
        columnId: "country",
        renderHeaderCell: () => "Country",
        renderCell: ({ ban }) =>
          ban.country ? (
            <Text size={200}>{ban.country}</Text>
          ) : (
            <Text size={200} className={styles.emptyValue}>
              —
            </Text>
          ),
      }),
      createTableColumn<BanRow>({
        columnId: "banned_at",
        renderHeaderCell: () => "Banned At",
        renderCell: ({ ban }) => (
          <Text size={200}>{ban.banned_at ? formatTimestamp(ban.banned_at) : "—"}</Text>
        ),
      }),
      createTableColumn<BanRow>({
        columnId: "expires_at",
        renderHeaderCell: () => "Expires At",
        renderCell: ({ ban }) => (
          <Text size={200}>{ban.expires_at ? formatTimestamp(ban.expires_at) : "—"}</Text>
        ),
      }),
      createTableColumn<BanRow>({
        columnId: "actions",
        renderHeaderCell: () => "",
        renderCell: ({ ban, onUnban }) => (
          <Tooltip content={`Unban ${ban.ip}`} relationship="label">
            <Button
              size="small"
              appearance="subtle"
              icon={<DismissRegular />}
              onClick={() => { void onUnban(ban.ip); }}
              aria-label={`Unban ${ban.ip}`}
            />
          </Tooltip>
        ),
      }),
    ],
    [styles],
  );

  const rows: BanRow[] = items.map((ban) => ({
    ban,
    onUnban,
  }));

  const totalPages = pageSize > 0 ? Math.ceil(total / pageSize) : 1;

  return (
    <div className={sectionStyles.section}>
      {/* Section header */}
      <div className={styles.header}>
        <div className={styles.headerLeft}>
          <Text as="h2" size={500} weight="semibold">
            Currently Banned IPs
          </Text>
          <Badge appearance="tint">{String(total)}</Badge>
        </div>
        <Button
          size="small"
          appearance="subtle"
          icon={<ArrowClockwiseRegular />}
          onClick={() => { void onRefresh(); }}
          aria-label="Refresh banned IPs"
        />
      </div>

      {/* Toolbar */}
      <div className={styles.toolbar}>
        <div className={styles.searchField}>
          <Field label="Search by IP">
            <Input
              aria-label="Search by IP"
              contentBefore={<SearchRegular />}
              placeholder="e.g. 192.168"
              value={search}
              onChange={(_, d) => {
                onSearch(d.value);
              }}
            />
          </Field>
        </div>
      </div>

      {/* Error bars */}
      {error && (
        <MessageBar intent="error">
          <MessageBarBody>{error}</MessageBarBody>
        </MessageBar>
      )}
      {opError && (
        <MessageBar intent="error">
          <MessageBarBody>{opError}</MessageBarBody>
        </MessageBar>
      )}

      {/* Table */}
      {loading ? (
        <div className={styles.centred}>
          <Spinner label="Loading banned IPs…" />
        </div>
      ) : items.length === 0 ? (
        <div className={styles.centred}>
          <Text size={200} className={styles.emptyText}>
            No IPs currently banned in this jail.
          </Text>
        </div>
      ) : (
        <div className={styles.tableWrapper}>
          <DataGrid
            items={rows}
            columns={columns}
            getRowId={(row: BanRow) => row.ban.ip}
            focusMode="composite"
          >
            <DataGridHeader>
              <DataGridRow>
                {({ renderHeaderCell }) => (
                  <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
                )}
              </DataGridRow>
            </DataGridHeader>
            <DataGridBody<BanRow>>
              {({ item, rowId }) => (
                <DataGridRow<BanRow> key={rowId}>
                  {({ renderCell }) => (
                    <DataGridCell>{renderCell(item)}</DataGridCell>
                  )}
                </DataGridRow>
              )}
            </DataGridBody>
          </DataGrid>
        </div>
      )}

      {/* Pagination */}
      {total > 0 && (
        <div className={styles.pagination}>
          <div className={styles.pageSizeWrapper}>
            <Text size={200}>Rows per page:</Text>
            <Dropdown
              aria-label="Rows per page"
              value={String(pageSize)}
              selectedOptions={[String(pageSize)]}
              onOptionSelect={(_, d) => {
                const newSize = Number(d.optionValue);
                if (!Number.isNaN(newSize)) {
                  onPageSizeChange(newSize);
                  onPageChange(1);
                }
              }}
              className={styles.rowsPerPageDropdown}
            >
              {PAGE_SIZE_OPTIONS.map((n) => (
                <Option key={n} value={String(n)}>
                  {String(n)}
                </Option>
              ))}
            </Dropdown>
          </div>

          <Text size={200}>
            {String((page - 1) * pageSize + 1)}–
            {String(Math.min(page * pageSize, total))} of {String(total)}
          </Text>

          <Button
            size="small"
            appearance="subtle"
            icon={<ChevronLeftRegular />}
            disabled={page <= 1}
            onClick={() => {
              onPageChange(Math.max(1, page - 1));
            }}
            aria-label="Previous page"
          />
          <Button
            size="small"
            appearance="subtle"
            icon={<ChevronRightRegular />}
            disabled={page >= totalPages}
            onClick={() => {
              onPageChange(page + 1);
            }}
            aria-label="Next page"
          />
        </div>
      )}
    </div>
  );
}
