/**
 * MapPage — geographical overview of fail2ban bans.
 *
 * Shows a clickable SVG world map coloured by ban density, a time-range
 * selector, and a companion table filtered by the selected country (or all
 * bans when no country is selected).
 */

import { useState, useMemo, useEffect } from "react";
import {
  Button,
  MessageBar,
  MessageBarBody,
  Spinner,
  Text,
  makeStyles,
  tokens,
} from "@fluentui/react-components";
import {
  ArrowCounterclockwiseRegular,
  DismissRegular,
} from "@fluentui/react-icons";
import { DashboardFilterBar } from "../components/DashboardFilterBar";
import { WorldMap } from "../components/WorldMap";
import { useMapData } from "../hooks/useMapData";
import { useMapColorThresholds } from "../hooks/useMapColorThresholds";
import { MapBansTable } from "./map/MapBansTable";
import type { TimeRange } from "../types/map";
import type { BanOriginFilter } from "../types/ban";

// ---------------------------------------------------------------------------
// 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,
  },
  tableWrapper: {
    overflow: "auto",
    maxHeight: "420px",
    borderRadius: tokens.borderRadiusMedium,
    border: `1px solid ${tokens.colorNeutralStroke1}`,
  },
  stickyHeaderCell: {
    position: "sticky",
    top: 0,
    zIndex: 1,
    backgroundColor: tokens.colorNeutralBackground1,
    boxShadow: `0 1px 0 ${tokens.colorNeutralStroke2}`,
  },
  filterBar: {
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    gap: tokens.spacingHorizontalM,
    padding: tokens.spacingVerticalS,
    borderRadius: tokens.borderRadiusMedium,
    backgroundColor: tokens.colorNeutralBackground2,
  },
  pagination: {
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    gap: tokens.spacingHorizontalS,
    padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,
    borderTop: `1px solid ${tokens.colorNeutralStroke2}`,
    backgroundColor: tokens.colorNeutralBackground2,
    position: "sticky",
    bottom: 0,
    zIndex: 1,
  },
});

// ---------------------------------------------------------------------------
// MapPage
// ---------------------------------------------------------------------------

export function MapPage(): React.JSX.Element {
  const styles = useStyles();
  const [range, setRange] = useState<TimeRange>("24h");
  const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all");
  const [selectedCountry, setSelectedCountry] = useState<string | null>(null);
  const [page, setPage] = useState<number>(1);
  const [pageSize, setPageSize] = useState<number>(100);

  const source = range === "24h" ? "fail2ban" : "archive";

  const { countries, countryNames, bans, total, loading, error, refresh } =
    useMapData(range, originFilter, source, selectedCountry ?? undefined);

  // True after the first successful data load — keeps the map mounted
  // during subsequent re-fetches so country selection gives instant feedback.
  const [hasLoadedOnce, setHasLoadedOnce] = useState(false);
  useEffect(() => {
    if (!loading && !error) setHasLoadedOnce(true);
  }, [loading, error]);

  const {
    thresholds: mapThresholds,
    error: mapThresholdError,
  } = useMapColorThresholds();

  const thresholdLow = mapThresholds?.threshold_low ?? 20;
  const thresholdMedium = mapThresholds?.threshold_medium ?? 50;
  const thresholdHigh = mapThresholds?.threshold_high ?? 100;

  useEffect(() => {
    if (mapThresholdError) {
      // Silently fall back to defaults if fetch fails
      console.warn("Failed to load map color thresholds:", mapThresholdError);
    }
  }, [mapThresholdError]);

  useEffect(() => {
    setPage(1);
  }, [range, originFilter, selectedCountry, bans, pageSize]);

  /** Bans visible in the companion table (filtered by selected country). */
  const visibleBans = useMemo(() => {
    if (!selectedCountry) return bans;
    return bans.filter((b) => b.country_code === selectedCountry);
  }, [bans, selectedCountry]);

  const selectedCountryName = selectedCountry
    ? (countryNames[selectedCountry] ?? selectedCountry)
    : null;

  const totalPages = Math.max(1, Math.ceil(visibleBans.length / pageSize));
  const hasPrev = page > 1;
  const hasNext = page < totalPages;

  const pageBans = useMemo(() => {
    const start = (page - 1) * pageSize;
    return visibleBans.slice(start, start + pageSize);
  }, [visibleBans, page, pageSize]);

  return (
    <div className={styles.root}>
      {/* ---------------------------------------------------------------- */}
      {/* Header row                                                        */}
      {/* ---------------------------------------------------------------- */}
      <div className={styles.header}>
        <Text as="h1" size={700} weight="semibold">
          World Map
        </Text>

        <div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalM, flexWrap: "wrap" }}>
          <DashboardFilterBar
            timeRange={range}
            onTimeRangeChange={(value) => {
              setRange(value);
              setSelectedCountry(null);
            }}
            originFilter={originFilter}
            onOriginFilterChange={(value) => {
              setOriginFilter(value);
              setSelectedCountry(null);
            }}
          />
          <Button
            icon={<ArrowCounterclockwiseRegular />}
            onClick={(): void => {
              refresh();
            }}
            disabled={loading}
            title="Refresh"
          />
        </div>
      </div>

      {/* ---------------------------------------------------------------- */}
      {/* Error / loading states                                            */}
      {/* ---------------------------------------------------------------- */}
      {error && (
        <MessageBar intent="error">
          <MessageBarBody>{error}</MessageBarBody>
        </MessageBar>
      )}

      {/* Initial load spinner — only shown before the first data arrives. */}
      {loading && !error && !hasLoadedOnce && (
        <div style={{ display: "flex", justifyContent: "center", padding: tokens.spacingVerticalXL }}>
          <Spinner label="Loading map data…" />
        </div>
      )}

      {/* ---------------------------------------------------------------- */}
      {/* World map                                                         */}
      {/* Keep the map mounted after first load so clicking a country gives */}
      {/* immediate visual feedback before the filtered data arrives.       */}
      {/* ---------------------------------------------------------------- */}
      {!error && hasLoadedOnce && (
        <WorldMap
          countries={countries}
          countryNames={countryNames}
          selectedCountry={selectedCountry}
          onSelectCountry={setSelectedCountry}
          thresholdLow={thresholdLow}
          thresholdMedium={thresholdMedium}
          thresholdHigh={thresholdHigh}
        />
      )}

      {/* ---------------------------------------------------------------- */}
      {/* Active country filter info bar                                    */}
      {/* ---------------------------------------------------------------- */}
      {selectedCountry && (
        <div className={styles.filterBar}>
          <Text size={300}>
            Showing <strong>{String(visibleBans.length)}</strong> bans from{" "}
            <strong>{selectedCountryName ?? selectedCountry}</strong>
            {" "}({String(countries[selectedCountry] ?? 0)} total in window)
          </Text>
          <Button
            appearance="subtle"
            size="small"
            icon={<DismissRegular />}
            onClick={(): void => {
              setSelectedCountry(null);
            }}
          >
            Clear filter
          </Button>
        </div>
      )}

      {/* ---------------------------------------------------------------- */}
      {/* Summary line                                                      */}
      {/* ---------------------------------------------------------------- */}
      {!error && hasLoadedOnce && (
        <div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalS }}>
          <Text size={300} style={{ color: tokens.colorNeutralForeground3 }}>
            {String(total)} total ban{total !== 1 ? "s" : ""} in the selected period
            {" · "}
            {String(Object.keys(countries).length)} countr{Object.keys(countries).length !== 1 ? "ies" : "y"} affected
          </Text>
          {loading && <Spinner size="tiny" />}
        </div>
      )}

      {/* ---------------------------------------------------------------- */}
      {/* Companion bans table                                              */}
      {/* ---------------------------------------------------------------- */}
      {!error && hasLoadedOnce && (
        <div className={styles.tableWrapper} style={{ opacity: loading ? 0.5 : 1, transition: "opacity 150ms" }}>
          <MapBansTable
            pageBans={pageBans}
            visibleCount={visibleBans.length}
            page={page}
            pageSize={pageSize}
            totalPages={totalPages}
            hasPrev={hasPrev}
            hasNext={hasNext}
            onPageChange={setPage}
            onPageSizeChange={setPageSize}
          />
        </div>
      )}
    </div>
  );
}
