/**
 * FiltersTab — master/detail layout for filter.d discovery and editing.
 *
 * Left pane: filter names with Active/Inactive badges (active filters sorted
 * to the top).  Active badge also shows which jails reference the filter.
 * Right pane: structured filter editor, "Assign to Jail" button, and a
 * collapsible raw-config editor.
 *
 * A "Create Filter" button at the top of the list pane opens a dialog for
 * creating a new ``filter.d/*.local`` file.
 */

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
  Button,
  Field,
  Input,
  MessageBar,
  MessageBarBody,
  Skeleton,
  SkeletonItem,
  tokens,
} from "@fluentui/react-components";
import { Add24Regular, LinkEdit24Regular } from "@fluentui/react-icons";
import { fetchFilterFile, fetchFilters, updateFilterFile } from "../../api/config";
import type { ConfFileUpdateRequest, FilterConfig } from "../../types/config";
import { AssignFilterDialog } from "./AssignFilterDialog";
import { ConfigListDetail } from "./ConfigListDetail";
import { CreateFilterDialog } from "./CreateFilterDialog";
import { FilterForm } from "./FilterForm";
import { RawConfigSection } from "./RawConfigSection";
import { useConfigStyles } from "./configStyles";

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

/**
 * Build the badge label text shown next to each filter in the list pane.
 *
 * Active filters that are used by one or more jails display the jail names,
 * e.g. ``"Active — sshd, apache-auth"``.
 */
function filterBadgeLabel(f: FilterConfig): string {
  if (!f.active) return "Inactive";
  if (f.used_by_jails.length === 0) return "Active";
  return `Active — ${f.used_by_jails.join(", ")}`;
}

// ---------------------------------------------------------------------------
// FilterDetail — right-pane detail for a selected filter
// ---------------------------------------------------------------------------

interface FilterDetailProps {
  filter: FilterConfig;
  onAssignClick: () => void;
}

/**
 * Detail pane for a selected filter: shows meta information, the structured
 * editor, an "Assign to Jail" action, and a raw-config section.
 *
 * @param props - Component props.
 * @returns JSX element.
 */
function FilterDetail({
  filter,
  onAssignClick,
}: FilterDetailProps): React.JSX.Element {
  const styles = useConfigStyles();

  const fetchRaw = useCallback(async (): Promise<string> => {
    const result = await fetchFilterFile(filter.name);
    return result.content;
  }, [filter.name]);

  const saveRaw = useCallback(
    async (content: string): Promise<void> => {
      const req: ConfFileUpdateRequest = { content };
      await updateFilterFile(filter.name, req);
    },
    [filter.name],
  );

  return (
    <div>
      {/* Meta information row */}
      <div className={styles.fieldRow} style={{ marginBottom: tokens.spacingVerticalS }}>
        <Field label="Source file">
          <Input
            readOnly
            value={filter.source_file || filter.filename}
            className={styles.codeInput}
            size="small"
          />
        </Field>
      </div>

      {/* Structured editor */}
      <FilterForm name={filter.name} />

      {/* Assign to jail action */}
      <div style={{ marginTop: tokens.spacingVerticalM }}>
        <Button
          appearance="secondary"
          icon={<LinkEdit24Regular />}
          onClick={onAssignClick}
        >
          Assign to Jail
        </Button>
      </div>

      {/* Raw config */}
      <div style={{ marginTop: tokens.spacingVerticalL }}>
        <RawConfigSection
          fetchContent={fetchRaw}
          saveContent={saveRaw}
          label="Raw Filter Configuration"
        />
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// FiltersTab (public export)
// ---------------------------------------------------------------------------

/**
 * Tab component for exploring and editing fail2ban filter definitions.
 *
 * @returns JSX element.
 */
export function FiltersTab(): React.JSX.Element {
  const [filters, setFilters] = useState<FilterConfig[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [selectedName, setSelectedName] = useState<string | null>(null);
  const [assignOpen, setAssignOpen] = useState(false);
  const [createOpen, setCreateOpen] = useState(false);
  const abortRef = useRef<AbortController | null>(null);

  const loadFilters = useCallback((): void => {
    abortRef.current?.abort();
    const ctrl = new AbortController();
    abortRef.current = ctrl;
    setLoading(true);
    setError(null);

    fetchFilters()
      .then((resp) => {
        if (!ctrl.signal.aborted) {
          setFilters(resp.filters);
          setLoading(false);
        }
      })
      .catch((err: unknown) => {
        if (!ctrl.signal.aborted) {
          setError(err instanceof Error ? err.message : "Failed to load filters");
          setLoading(false);
        }
      });
  }, []);

  useEffect(() => {
    loadFilters();
    return (): void => {
      abortRef.current?.abort();
    };
  }, [loadFilters]);

  /** The full FilterConfig for the currently selected name. */
  const selectedFilter = useMemo(
    () => filters.find((f) => f.name === selectedName) ?? null,
    [filters, selectedName],
  );

  const handleAssigned = useCallback((): void => {
    setAssignOpen(false);
    // Refresh filter list so active status is up-to-date.
    loadFilters();
  }, [loadFilters]);

  const handleCreated = useCallback(
    (newFilter: FilterConfig): void => {
      setCreateOpen(false);
      setFilters((prev) => [...prev, newFilter]);
      setSelectedName(newFilter.name);
    },
    [],
  );

  if (loading) {
    return (
      <Skeleton aria-label="Loading filters…">
        {[0, 1, 2].map((i) => (
          <SkeletonItem key={i} size={40} style={{ marginBottom: 4 }} />
        ))}
      </Skeleton>
    );
  }

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

  const listHeader = (
    <Button
      appearance="outline"
      icon={<Add24Regular />}
      size="small"
      onClick={() => { setCreateOpen(true); }}
    >
      Create Filter
    </Button>
  );

  return (
    <>
      <ConfigListDetail
        items={filters}
        isActive={(f) => f.active}
        itemBadgeLabel={filterBadgeLabel}
        selectedName={selectedName}
        onSelect={setSelectedName}
        loading={false}
        error={null}
        listHeader={listHeader}
      >
        {selectedFilter !== null && (
          <FilterDetail
            key={selectedFilter.name}
            filter={selectedFilter}
            onAssignClick={() => { setAssignOpen(true); }}
          />
        )}
      </ConfigListDetail>

      <AssignFilterDialog
        filterName={selectedName}
        open={assignOpen}
        onClose={() => { setAssignOpen(false); }}
        onAssigned={handleAssigned}
      />

      <CreateFilterDialog
        open={createOpen}
        onClose={() => { setCreateOpen(false); }}
        onCreate={handleCreated}
      />
    </>
  );
}
