import { useEffect, useMemo, useState } from "react";
import { Toaster, toast } from "sonner";
import CanvasPane, { CanvasThumbnail } from "./components/CanvasPane.jsx";
import Controls from "./components/Controls.jsx";
import HistogramPanel from "./components/HistogramPanel.jsx";
import { applyStateOperation, combineStates, deleteState, getOperations, listStates, uploadImage } from "./lib/api.js";

function showErrorToast(error, fallback = "Something went wrong.") {
  const message = error?.message || fallback;
  toast.error(message, {
    description: "Please check the selected image, operation, and parameters."
  });
  return message;
}

export default function App() {
  const [session, setSession] = useState(null);
  const [states, setStates] = useState([]);
  const [activeState, setActiveState] = useState(null);
  const [operations, setOperations] = useState([]);
  const [selectedOperation, setSelectedOperation] = useState("");
  const [params, setParams] = useState({});
  const [selectedStateIds, setSelectedStateIds] = useState([]);
  const [status, setStatus] = useState("Upload an image to begin.");
  const [busy, setBusy] = useState(false);
  const [transform, setTransform] = useState({ x: 0, y: 0, scale: 1 });

  useEffect(() => {
    getOperations()
      .then((payload) => {
        setOperations(payload.operations || []);
        const first = payload.operations?.[0];
        if (first) {
          setSelectedOperation(first.id);
          setParams({ _repeat: 1, ...Object.fromEntries(Object.entries(first.params || {}).map(([key, schema]) => [key, schema.default])) });
        }
      })
      .catch((error) => setStatus(showErrorToast(error, "Unable to load operations.")));
  }, []);

  async function refreshStates(sessionId, nextActiveId = null) {
    const payload = await listStates(sessionId);
    setStates(payload.states || []);
    const nextActive = payload.states?.find((state) => state.state_id === nextActiveId) || payload.states?.at(-1) || null;
    setActiveState(nextActive);
    return nextActive;
  }

  async function handleUpload(file) {
    if (!file) return;
    setBusy(true);
    setStatus("Uploading image...");
    try {
      const payload = await uploadImage(file);
      setSession(payload);
      const initialStates = payload.states || [];
      setStates(initialStates);
      setActiveState(initialStates[0] || null);
      setSelectedStateIds(initialStates[0] ? [initialStates[0].state_id] : []);
      setTransform({ x: 0, y: 0, scale: 1 });
      setStatus(`${payload.width} x ${payload.height} ${payload.color_mode} image loaded as S0.`);
    } catch (error) {
      setStatus(showErrorToast(error, "Unable to upload image."));
    } finally {
      setBusy(false);
    }
  }

  function handleSelectOperation(operationId, nextParams) {
    setSelectedOperation(operationId);
    setParams(nextParams);
  }

  function handleParamChange(key, value) {
    setParams((current) => ({ ...current, [key]: value }));
  }

  async function handleApply() {
    if (!activeState || !selectedOperation) return;
    setBusy(true);
    setStatus(`Applying ${selectedOperation} to ${activeState.label}...`);
    try {
      const state = await applyStateOperation(activeState.state_id, selectedOperation, params);
      await refreshStates(state.session_id, state.state_id);
      setSelectedStateIds([state.state_id]);
      setStatus(`${state.label} created.`);
    } catch (error) {
      setStatus(showErrorToast(error, "Unable to apply operation."));
    } finally {
      setBusy(false);
    }
  }

  async function handleCombine(kind) {
    if (selectedStateIds.length < 2) return;
    setBusy(true);
    setStatus(`Combining ${selectedStateIds.length} states using ${kind}...`);
    try {
      const state = await combineStates(kind, selectedStateIds);
      await refreshStates(state.session_id, state.state_id);
      setSelectedStateIds([state.state_id]);
      setStatus(`${state.label} created.`);
    } catch (error) {
      setStatus(showErrorToast(error, "Unable to combine states."));
    } finally {
      setBusy(false);
    }
  }

  function toggleCombineState(stateId) {
    setSelectedStateIds((current) => current.includes(stateId) ? current.filter((id) => id !== stateId) : [...current, stateId]);
  }

  async function handleDeleteState(state) {
    if (!state || !session) return;
    setBusy(true);
    setStatus(`Deleting ${state.label}...`);
    try {
      await deleteState(state.state_id);
      const remaining = await listStates(session.session_id);
      const nextStates = remaining.states || [];
      setStates(nextStates);
      const currentActive = nextStates.find((item) => item.state_id === activeState?.state_id);
      const fallback = activeState?.state_id === state.state_id ? nextStates.at(-1) || nextStates[0] || null : currentActive || nextStates.at(-1) || nextStates[0] || null;
      setActiveState(fallback);
      setSelectedStateIds((current) => current.filter((id) => id !== state.state_id));
      setStatus(`${state.label} deleted.`);
    } catch (error) {
      setStatus(showErrorToast(error, "Unable to delete state."));
    } finally {
      setBusy(false);
    }
  }

  const originalState = states[0] || null;
  const viewportTitle = useMemo(() => {
    if (!activeState) return "No active state";
    return `${activeState.label} - ${activeState.width} x ${activeState.height} ${activeState.color_mode}`;
  }, [activeState]);

  return (
    <div className="flex h-screen overflow-hidden bg-zinc-950 text-zinc-100">
      <Toaster richColors theme="dark" position="top-right" closeButton />
      <Controls
        operations={operations}
        selectedOperation={selectedOperation}
        params={params}
        states={states}
        activeState={activeState}
        selectedStateIds={selectedStateIds}
        busy={busy}
        onUpload={handleUpload}
        onSelectOperation={handleSelectOperation}
        onParamChange={handleParamChange}
        onApply={handleApply}
        onSelectState={(state) => {
          setActiveState(state);
        }}
        onToggleCombineState={toggleCombineState}
        onCombine={handleCombine}
        onDeleteState={handleDeleteState}
      />

      <main className="flex h-screen min-w-0 flex-1 flex-col overflow-hidden">
        <header className="flex flex-wrap items-center justify-between gap-3 border-b border-zinc-800 bg-zinc-950 px-5 py-3">
          <div>
            <p className="text-xs uppercase tracking-[0.18em] text-cyan-300">Professor Slide Workspace</p>
            <h2 className="text-sm font-medium text-zinc-200">{viewportTitle}</h2>
          </div>
          <div className="text-sm text-zinc-400">{busy ? "Working..." : status}</div>
        </header>

        <div className="relative min-h-0 flex-1 overflow-hidden bg-zinc-800">
          <CanvasThumbnail title="S0 Original" imageData={originalState?.image_data} />
          <CanvasPane
            title="Active State"
            imageData={activeState?.image_data}
            histogram={activeState?.histogram}
            transform={transform}
            onTransform={setTransform}
          />
        </div>

        <HistogramPanel original={originalState?.histogram} processed={activeState?.histogram} />
      </main>
    </div>
  );
}
