/**
 * FilterForm — structured form editor for a single ``filter.d/*.conf`` file.
 *
 * Displays parsed fields grouped into collapsible sections:
 * - Includes (before / after)
 * - Variables ([DEFAULT] key-value pairs)
 * - Definition (prefregex, failregex, ignoreregex, optional advanced fields)
 *
 * Provides a Save button and shows saving/error state.
 */

import { useEffect, useMemo, useState } from "react";
import {
  Accordion,
  AccordionHeader,
  AccordionItem,
  AccordionPanel,
  Button,
  Field,
  Input,
  MessageBar,
  MessageBarBody,
  Skeleton,
  SkeletonItem,
  Text,
  Textarea,
} from "@fluentui/react-components";
import { Add24Regular, Delete24Regular } from "@fluentui/react-icons";
import type { FilterConfig, FilterConfigUpdate } from "../../types/config";
import { useFilterConfig } from "../../hooks/useFilterConfig";
import { useAutoSave } from "../../hooks/useAutoSave";
import { AutoSaveIndicator } from "./AutoSaveIndicator";
import { RegexList } from "./RegexList";
import { useConfigStyles } from "./configStyles";

// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------

/** Simple editable key-value table for [DEFAULT] variables. */
interface KVEditorProps {
  entries: Record<string, string>;
  onChange: (next: Record<string, string>) => void;
}

function KVEditor({ entries, onChange }: KVEditorProps): React.JSX.Element {
  const styles = useConfigStyles();
  const rows = Object.entries(entries);

  const handleKeyChange = (oldKey: string, newKey: string): void => {
    const next: Record<string, string> = {};
    for (const [k, v] of Object.entries(entries)) {
      next[k === oldKey ? newKey : k] = v;
    }
    onChange(next);
  };

  const handleValueChange = (key: string, value: string): void => {
    onChange({ ...entries, [key]: value });
  };

  const handleDelete = (key: string): void => {
    const { [key]: _removed, ...rest } = entries;
    onChange(rest);
  };

  const handleAdd = (): void => {
    let newKey = "new_var";
    let n = 1;
    while (newKey in entries) {
      newKey = `new_var_${String(n)}`;
      n++;
    }
    onChange({ ...entries, [newKey]: "" });
  };

  return (
    <div>
      {rows.map(([key, value]) => (
        <div key={key} className={styles.fieldRow}>
          <Input
            value={key}
            size="small"
            style={{ width: 160, fontFamily: "monospace" }}
            aria-label={`Variable name: ${key}`}
            onChange={(_e, d) => { handleKeyChange(key, d.value); }}
          />
          <Input
            value={value}
            size="small"
            style={{ flex: 1, fontFamily: "monospace" }}
            aria-label={`Value for ${key}`}
            onChange={(_e, d) => { handleValueChange(key, d.value); }}
          />
          <Button
            icon={<Delete24Regular />}
            size="small"
            appearance="subtle"
            onClick={() => { handleDelete(key); }}
            aria-label={`Delete variable ${key}`}
          />
        </div>
      ))}
      <Button
        icon={<Add24Regular />}
        size="small"
        appearance="outline"
        onClick={handleAdd}
        style={{ marginTop: 4 }}
      >
        Add variable
      </Button>
    </div>
  );
}

// ---------------------------------------------------------------------------
// FilterFormEditor — rendered once config is loaded
// ---------------------------------------------------------------------------

interface FilterFormEditorProps {
  config: FilterConfig;
  onSave: (update: FilterConfigUpdate) => Promise<void>;
}

function FilterFormEditor({
  config,
  onSave,
}: FilterFormEditorProps): React.JSX.Element {
  const styles = useConfigStyles();

  // Local draft state — initialised from the loaded config.
  const [before, setBefore] = useState(config.before ?? "");
  const [after, setAfter] = useState(config.after ?? "");
  const [variables, setVariables] = useState<Record<string, string>>(config.variables);
  const [prefregex, setPrefregex] = useState(config.prefregex ?? "");
  const [failregex, setFailregex] = useState<string[]>(config.failregex);
  const [ignoreregex, setIgnoreregex] = useState<string[]>(config.ignoreregex);
  const [maxlines, setMaxlines] = useState(
    config.maxlines !== null ? String(config.maxlines) : ""
  );
  const [datepattern, setDatepattern] = useState(config.datepattern ?? "");
  const [journalmatch, setJournalmatch] = useState(config.journalmatch ?? "");

  // Reset draft whenever a freshly-loaded config arrives.
  useEffect(() => {
    setBefore(config.before ?? "");
    setAfter(config.after ?? "");
    setVariables(config.variables);
    setPrefregex(config.prefregex ?? "");
    setFailregex(config.failregex);
    setIgnoreregex(config.ignoreregex);
    setMaxlines(config.maxlines !== null ? String(config.maxlines) : "");
    setDatepattern(config.datepattern ?? "");
    setJournalmatch(config.journalmatch ?? "");
  }, [config]);

  const autoSavePayload = useMemo<FilterConfigUpdate>(() => {
    const parsedMax = maxlines.trim() !== "" ? parseInt(maxlines, 10) : null;
    return {
      before: before.trim() || null,
      after: after.trim() || null,
      variables,
      prefregex: prefregex.trim() || null,
      failregex,
      ignoreregex,
      maxlines: parsedMax !== null && !isNaN(parsedMax) ? parsedMax : null,
      datepattern: datepattern.trim() || null,
      journalmatch: journalmatch.trim() || null,
    };
  }, [after, before, datepattern, failregex, ignoreregex, journalmatch, maxlines, prefregex, variables]);

  const { status: saveStatus, errorText: saveErrorText, retry: retrySave } =
    useAutoSave(autoSavePayload, onSave);

  const hasIncludes = config.before !== null || config.after !== null;
  const varCount = Object.keys(variables).length;

  return (
    <div>
      <div className={styles.buttonRow} style={{ marginBottom: 8 }}>
        <Text size={500} weight="semibold">
          {config.filename}
        </Text>
        <AutoSaveIndicator
          status={saveStatus}
          errorText={saveErrorText}
          onRetry={retrySave}
        />
      </div>

      <Accordion multiple collapsible defaultOpenItems={["definition"]}>
        {/* Includes */}
        <AccordionItem value="includes" className={styles.accordionItem}>
          <AccordionHeader>
            {`Includes${hasIncludes ? "" : " (none)"}`}
          </AccordionHeader>
          <AccordionPanel>
            <div className={styles.sectionCard}>
              <Field label="before">
                <Input
                  value={before}
                  onChange={(_e, d) => { setBefore(d.value); }}
                  placeholder="e.g. common.conf"
                  className={styles.codeInput}
                />
              </Field>
              <Field label="after">
                <Input
                  value={after}
                  onChange={(_e, d) => { setAfter(d.value); }}
                  placeholder="e.g. sshd-aggressive.conf"
                  className={styles.codeInput}
                />
              </Field>
            </div>
          </AccordionPanel>
        </AccordionItem>

        {/* Variables */}
        <AccordionItem value="variables" className={styles.accordionItem}>
          <AccordionHeader>
            {`Variables (${String(varCount)})`}
          </AccordionHeader>
          <AccordionPanel>
            <div className={styles.sectionCard}>
              <KVEditor entries={variables} onChange={setVariables} />
            </div>
          </AccordionPanel>
        </AccordionItem>

        {/* Definition */}
        <AccordionItem value="definition" className={styles.accordionItem}>
          <AccordionHeader>Definition</AccordionHeader>
          <AccordionPanel>
            <div className={styles.sectionCard}>
              <Field label="prefregex">
                <Textarea
                  value={prefregex}
                  onChange={(_e, d) => { setPrefregex(d.value); }}
                  placeholder="Prefix regex prepended to all failregex patterns"
                  className={styles.codeInput}
                  rows={2}
                />
              </Field>

              <RegexList label="failregex" patterns={failregex} onChange={setFailregex} />
              <RegexList label="ignoreregex" patterns={ignoreregex} onChange={setIgnoreregex} />

              {/* Advanced optional fields */}
              <details style={{ marginTop: 12 }}>
                <summary style={{ cursor: "pointer", userSelect: "none", marginBottom: 8 }}>
                  Advanced options
                </summary>
                <Field label="maxlines">
                  <Input
                    type="number"
                    value={maxlines}
                    onChange={(_e, d) => { setMaxlines(d.value); }}
                    placeholder="e.g. 10"
                    style={{ width: 100 }}
                  />
                </Field>
                <Field label="datepattern">
                  <Input
                    value={datepattern}
                    onChange={(_e, d) => { setDatepattern(d.value); }}
                    placeholder="e.g. %Y-%m-%d %H:%M:%S"
                    className={styles.codeInput}
                  />
                </Field>
                <Field label="journalmatch">
                  <Input
                    value={journalmatch}
                    onChange={(_e, d) => { setJournalmatch(d.value); }}
                    placeholder="e.g. _SYSTEMD_UNIT=sshd.service"
                    className={styles.codeInput}
                  />
                </Field>
              </details>
            </div>
          </AccordionPanel>
        </AccordionItem>
      </Accordion>
    </div>
  );
}

// ---------------------------------------------------------------------------
// FilterForm (public export)
// ---------------------------------------------------------------------------

export interface FilterFormProps {
  /** Filter base name (e.g. ``"sshd"``). */
  name: string;
}

/**
 * Loads and renders the structured form editor for one filter.
 * Shows a spinner while loading and an error message on failure.
 */
export function FilterForm({ name }: FilterFormProps): React.JSX.Element {
  const { config, loading, error, save } = useFilterConfig(name);

  if (loading) {
    return (
      <Skeleton aria-label={`Loading ${name}…`}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginBottom: 8 }}>
          <SkeletonItem size={32} />
          <SkeletonItem size={32} />
        </div>
        <SkeletonItem size={32} style={{ marginBottom: 8 }} />
        <SkeletonItem size={72} />
      </Skeleton>
    );
  }

  if (error !== null || config === null) {
    return (
      <MessageBar intent="error">
        <MessageBarBody>{error ?? "Failed to load filter config"}</MessageBarBody>
      </MessageBar>
    );
  }

  return (
    <FilterFormEditor
      config={config}
      onSave={save}
    />
  );
}
