"use client";

import { useCallback, useEffect, useState } from "react";
import { createClient, getBrowserUserId } from "@/lib/supabase/client";
import type { JournalEntry, JournalTemplate } from "@/types";

export function useJournal() {
  const [entries, setEntries] = useState<JournalEntry[]>([]);
  const [template, setTemplate] = useState<JournalTemplate | null>(null);
  const [loading, setLoading] = useState(true);
  const [userId, setUserId] = useState<string | null>(null);
  const supabase = createClient();

  useEffect(() => {
    void getBrowserUserId().then(setUserId).catch(() => setUserId(null));
  }, []);

  const fetchTemplate = useCallback(async () => {
    const { data } = await supabase
      .from("journal_templates")
      .select("*")
      .maybeSingle();
    setTemplate(data);
  }, [supabase]);

  const fetchEntries = useCallback(async () => {
    const { data } = await supabase
      .from("journal_entries")
      .select("*")
      .order("entry_date", { ascending: false })
      .limit(100);
    setEntries(data || []);
    setLoading(false);
  }, [supabase]);

  useEffect(() => {
    const timer = window.setTimeout(() => {
      void fetchTemplate();
      void fetchEntries();
    }, 0);

    return () => window.clearTimeout(timer);
  }, [fetchTemplate, fetchEntries]);

  async function saveTemplate(content: Record<string, unknown>) {
    if (!userId) throw new Error("Not authenticated");

    if (template) {
      const { error } = await supabase
        .from("journal_templates")
        .update({ content })
        .eq("id", template.id);
      if (error) throw error;
      setTemplate({ ...template, content });
    } else {
      const { data, error } = await supabase
        .from("journal_templates")
        .insert({ user_id: userId, content })
        .select()
        .single();
      if (error) throw error;
      setTemplate(data);
    }
  }

  const getOrCreateEntry = useCallback(async (date: string): Promise<JournalEntry> => {
    if (!userId) throw new Error("Not authenticated");

    // Check DB directly to avoid stale closure issues
    const { data: existing } = await supabase
      .from("journal_entries")
      .select("*")
      .eq("user_id", userId)
      .eq("entry_date", date)
      .maybeSingle();

    if (existing) return existing as JournalEntry;

    // Return an unsaved draft only — no DB row yet. Merely navigating to a
    // day must not create an entry, or the streak counts empty days.
    // The row is only inserted once the user actually writes something
    // or sets a mood (see saveEntry).
    const initialContent = template?.content && Object.keys(template.content).length > 0
      ? template.content
      : { type: "doc", content: [{ type: "paragraph", content: [] }] };

    return {
      id: "",
      user_id: userId,
      entry_date: date,
      title: formatDateTitle(date),
      content: initialContent,
      mood: null,
      completed: false,
      created_at: "",
      updated_at: "",
    };
  }, [userId, supabase, template]);

  async function saveEntry(
    entry: JournalEntry,
    input: Partial<Pick<JournalEntry, "title" | "content" | "mood" | "completed">>
  ): Promise<JournalEntry> {
    if (entry.id) {
      const { error } = await supabase
        .from("journal_entries")
        .update(input)
        .eq("id", entry.id);
      if (error) throw error;
      const updated = { ...entry, ...input };
      setEntries((prev) => prev.map((e) => (e.id === entry.id ? updated : e)));
      return updated;
    }

    // First real write for this day — create the row now.
    const { data, error } = await supabase
      .from("journal_entries")
      .insert({
        user_id: entry.user_id,
        entry_date: entry.entry_date,
        title: entry.title,
        content: entry.content,
        mood: entry.mood,
        completed: entry.completed,
        ...input,
      })
      .select()
      .single();
    if (error) throw error;
    const saved = data as JournalEntry;
    setEntries((prev) => {
      if (prev.some((e) => e.entry_date === saved.entry_date)) return prev;
      return [saved, ...prev];
    });
    return saved;
  }

  async function deleteEntry(id: string) {
    const { error } = await supabase.from("journal_entries").delete().eq("id", id);
    if (error) throw error;
    setEntries((prev) => prev.filter((e) => e.id !== id));
  }

  return {
    entries,
    template,
    loading,
    saveTemplate,
    getOrCreateEntry,
    saveEntry,
    deleteEntry,
    refetch: fetchEntries,
  };
}

function formatDateTitle(date: string): string {
  const d = new Date(date + "T00:00:00");
  return d.toLocaleDateString("de-DE", {
    weekday: "long",
    day: "numeric",
    month: "long",
    year: "numeric",
  });
}
