"use client";

import { useEffect, useState } from "react";
import { createClient, getBrowserUserId } from "@/lib/supabase/client";

export type NodeColor = "amber" | "violet" | "emerald" | "sky" | "rose";

export interface MindNode {
  id: string;
  title: string;
  description: string;
  color: NodeColor;
  parentId: string | null;
  children: string[];
  manualPosition?: { x: number; y: number } | null;
}

export type MindDrawing =
  | { id: string; type: "sketch"; color: NodeColor; points: { x: number; y: number }[] }
  | { id: string; type: "line" | "arrow"; color: NodeColor; start: { x: number; y: number }; end: { x: number; y: number } };

export interface MindMap {
  id: string;
  title: string;
  rootId: string;
  nodes: Record<string, MindNode>;
  drawings: MindDrawing[];
}

interface DbRow {
  id: string;
  title: string;
  root_id: string;
  nodes: Record<string, MindNode>;
  drawings: MindDrawing[];
}

function rowToMap(row: DbRow): MindMap {
  return {
    id: row.id,
    title: row.title,
    rootId: row.root_id,
    nodes: Object.fromEntries(
      Object.entries(row.nodes ?? {}).map(([k, n]) => [
        k,
        { ...n, description: n.description ?? "", manualPosition: n.manualPosition ?? null },
      ])
    ),
    drawings: Array.isArray(row.drawings) ? row.drawings : [],
  };
}

function toMindMapError(error: unknown, fallback: string) {
  if (error instanceof Error && error.message) return new Error(error.message);

  if (error && typeof error === "object" && "message" in error) {
    const message = (error as { message?: unknown }).message;
    if (typeof message === "string" && message.trim()) return new Error(message);
  }

  return new Error(fallback);
}

export function useMindMaps() {
  const supabase = createClient();
  const [maps, setMaps] = useState<MindMap[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;

    async function loadMaps() {
      const { data } = await supabase
        .from("mind_maps")
        .select("id, title, root_id, nodes, drawings")
        .order("created_at", { ascending: true });

      if (cancelled) return;
      setMaps((data ?? []).map(rowToMap));
      setLoading(false);
    }

    void loadMaps();

    return () => {
      cancelled = true;
    };
  }, [supabase]);

  async function createMap(title: string, rootId: string, rootNode: MindNode): Promise<MindMap> {
    const userId = await getBrowserUserId();
    if (!userId) throw new Error("Not authenticated");

    const { data, error } = await supabase
      .from("mind_maps")
      .insert({ user_id: userId, title, root_id: rootId, nodes: { [rootId]: rootNode }, drawings: [] })
      .select("id, title, root_id, nodes, drawings")
      .single();
    if (error) throw toMindMapError(error, "Mind map could not be created.");
    const map = rowToMap(data as DbRow);
    setMaps((prev) => [...prev, map]);
    return map;
  }

  async function updateMap(id: string, patch: Partial<{ title: string; nodes: Record<string, MindNode>; drawings: MindDrawing[] }>) {
    const dbPatch: Record<string, unknown> = {};
    if (patch.title !== undefined) dbPatch.title = patch.title;
    if (patch.nodes !== undefined) dbPatch.nodes = patch.nodes;
    if (patch.drawings !== undefined) dbPatch.drawings = patch.drawings;

    const { error } = await supabase.from("mind_maps").update(dbPatch).eq("id", id);
    if (error) throw toMindMapError(error, "Mind map could not be updated.");

    setMaps((prev) =>
      prev.map((m) =>
        m.id !== id ? m : {
          ...m,
          title: patch.title ?? m.title,
          nodes: patch.nodes ?? m.nodes,
          drawings: patch.drawings ?? m.drawings,
        }
      )
    );
  }

  async function deleteMap(id: string) {
    const { error } = await supabase.from("mind_maps").delete().eq("id", id);
    if (error) throw toMindMapError(error, "Mind map could not be deleted.");
    setMaps((prev) => prev.filter((m) => m.id !== id));
  }

  return { maps, loading, createMap, updateMap, deleteMap };
}
