import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import * as api from "@/api/client";
import { useWindowManager } from "@/hooks/useWindowManager";
import { useKeyboardSave } from "@/hooks/useKeyboardSave";
import FloatingWindow from "@/components/shared/FloatingWindow";
import EditorPane from "@/components/editor/EditorPane";
import EditorPointer from "@/components/editor/EditorPointer";
import { iniHighlight } from "@/components/editor/iniHighlight";
import { Button } from "@/components/ui/button";
import type { ManagedWindow } from "@/hooks/useWindowManager";

// ---------------------------------------------------------------------------
// Settings view — config editors + restart
// ---------------------------------------------------------------------------

const iniExtensions = iniHighlight();

type ConfigKind = "reticulum" | "nomadnet";

interface ConfigWinData {
  kind: ConfigKind;
}

export default function SettingsView() {
  const {
    windows, focusedId,
    open, update, close, focus,
  } = useWindowManager<ConfigWinData>({ w: 560, h: 440 });

  const [restarting, setRestarting] = useState(false);

  const handleRestart = useCallback(async () => {
    setRestarting(true);
    try {
      const result = await api.restartServices();
      toast.success(
        result.nomadnet_restarted
          ? "NomadNet restarted"
          : "NomadNet container not found",
      );
    } catch {
      toast.error("Restart failed");
    } finally {
      setRestarting(false);
    }
  }, []);

  return (
    <div className="flex flex-col items-center justify-center h-full gap-4">
      <div className="flex flex-col gap-3 text-center">
        <h2 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Configuration</h2>
        <div className="flex gap-3">
          <Button
            variant="outline"
            onClick={() => open("reticulum", { kind: "reticulum" })}
          >
            Reticulum
          </Button>
          <Button
            variant="outline"
            onClick={() => open("nomadnet", { kind: "nomadnet" })}
          >
            NomadNet
          </Button>
        </div>
        <Button
          variant="default"
          disabled={restarting}
          onClick={handleRestart}
        >
          {restarting ? "Restarting..." : "Apply & Restart"}
        </Button>
      </div>

      {windows.map((win) => (
        <ConfigEditorWindow
          key={win.id}
          win={win}
          focused={focusedId === win.id}
          onUpdate={update}
          onClose={close}
          onFocus={focus}
        />
      ))}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Floating config editor window
// ---------------------------------------------------------------------------

const TITLES: Record<ConfigKind, string> = {
  reticulum: "Reticulum Config",
  nomadnet: "NomadNet Config",
};

function ConfigEditorWindow({
  win, focused, onUpdate, onClose, onFocus,
}: {
  win: ManagedWindow<ConfigWinData>;
  focused: boolean;
  onUpdate: (id: string, patch: Partial<ManagedWindow<ConfigWinData>>) => void;
  onClose: (id: string) => void;
  onFocus: (id: string) => void;
}) {
  const kind = win.data.kind;
  const windowRef = useRef<HTMLDivElement>(null);
  const [content, setContent] = useState<string | null>(null);
  const [isDirty, setIsDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const savedRef = useRef("");

  useEffect(() => {
    api.fetchConfig(kind).then((c) => {
      setContent(c);
      savedRef.current = c;
    }).catch(() => toast.error(`Failed to load ${kind} config`));
  }, [kind]);

  const handleChange = useCallback((v: string) => {
    setContent(v);
    setIsDirty(v !== savedRef.current);
  }, []);

  const handleSave = useCallback(async () => {
    if (content === null) return;
    setSaving(true);
    try {
      await api.saveConfig(kind, content);
      savedRef.current = content;
      setIsDirty(false);
      toast.success(`${TITLES[kind]} saved`);
    } catch {
      toast.error("Save failed");
    } finally {
      setSaving(false);
    }
  }, [content, kind]);

  useKeyboardSave(handleSave, undefined, focused);

  const handleClose = useCallback((id: string) => {
    if (isDirty && !window.confirm("You have unsaved changes. Close anyway?")) return;
    onClose(id);
  }, [isDirty, onClose]);

  return (
    <FloatingWindow
      id={win.id}
      title={TITLES[kind]}
      x={win.x} y={win.y} w={win.w} h={win.h}
      zIndex={win.zIndex}
      focused={focused}
      onUpdate={onUpdate}
      onClose={handleClose}
      onFocus={onFocus}
      minW={360} minH={250}
      containerRef={windowRef}
    >
      <EditorPointer containerRef={windowRef} focused={focused} />
      <div className="flex flex-col h-full">
        <div className="flex items-center px-3 py-1.5 border-b-2 border-border shrink-0 gap-2">
          <span className="text-xs font-semibold flex-1">
            {TITLES[kind]}
            {isDirty && <span className="text-muted-foreground ml-1.5">(unsaved)</span>}
          </span>
          <button
            onClick={handleSave}
            disabled={saving || !isDirty}
            className="text-[10px] uppercase tracking-wider text-muted-foreground hover:text-foreground disabled:opacity-40 transition-colors cursor-pointer"
          >
            {saving ? "Saving..." : "Save"}
          </button>
        </div>
        <div className="flex-1 min-h-0">
          {content !== null ? (
            <EditorPane value={content} onChange={handleChange} extensions={iniExtensions} />
          ) : (
            <div className="flex items-center justify-center h-full text-muted-foreground text-xs">
              Loading...
            </div>
          )}
        </div>
      </div>
    </FloatingWindow>
  );
}
