"use client";

import { useCallback, useEffect, useState } from "react";
import { createClient, getBrowserUserId } from "@/lib/supabase/client";
import type {
  FinanceBudget,
  FinanceCategory,
  FinanceCategoryType,
  FinanceRecurringFrequency,
  FinanceRecurringItem,
  FinanceTransaction,
  FinanceTransactionStatus,
  FinanceTransactionType,
} from "@/types";

export interface FinanceTransactionInput {
  type: FinanceTransactionType;
  title: string;
  description?: string;
  category: string;
  amount_cents: number;
  currency?: string;
  transaction_date: string;
  status?: FinanceTransactionStatus;
}

export interface FinanceBudgetInput {
  category: string;
  amount_cents: number;
  currency?: string;
  month: string;
}

export interface FinanceRecurringItemInput {
  type: FinanceTransactionType;
  title: string;
  category: string;
  amount_cents: number;
  currency?: string;
  frequency: FinanceRecurringFrequency;
  next_due_date: string;
  is_active?: boolean;
}

export interface FinanceCategoryInput {
  name: string;
  type?: FinanceCategoryType;
  color?: string;
  sort_order?: number;
}

export function useFinances() {
  const [transactions, setTransactions] = useState<FinanceTransaction[]>([]);
  const [budgets, setBudgets] = useState<FinanceBudget[]>([]);
  const [recurringItems, setRecurringItems] = useState<FinanceRecurringItem[]>([]);
  const [categories, setCategories] = useState<FinanceCategory[]>([]);
  const [loading, setLoading] = useState(true);
  const [userId, setUserId] = useState<string | null>(null);
  const supabase = createClient();

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

  async function requireCurrentUserId() {
    const currentUserId = userId || (await getBrowserUserId());
    if (currentUserId && currentUserId !== userId) {
      setUserId(currentUserId);
    }
    if (!currentUserId) throw new Error("Not authenticated");
    return currentUserId;
  }

  const fetchFinances = useCallback(async () => {
    setLoading(true);

    const [transactionsRes, budgetsRes, recurringRes, categoriesRes] = await Promise.all([
      supabase
        .from("finance_transactions")
        .select("*")
        .order("transaction_date", { ascending: false })
        .order("created_at", { ascending: false }),
      supabase
        .from("finance_budgets")
        .select("*")
        .order("month", { ascending: false })
        .order("category"),
      supabase
        .from("finance_recurring_items")
        .select("*")
        .order("is_active", { ascending: false })
        .order("next_due_date", { ascending: true }),
      supabase
        .from("finance_categories")
        .select("*")
        .order("sort_order")
        .order("name"),
    ]);

    if (transactionsRes.error) throw transactionsRes.error;
    if (budgetsRes.error) throw budgetsRes.error;
    if (recurringRes.error) throw recurringRes.error;
    if (categoriesRes.error) throw categoriesRes.error;

    setTransactions((transactionsRes.data || []) as FinanceTransaction[]);
    setBudgets((budgetsRes.data || []) as FinanceBudget[]);
    setRecurringItems((recurringRes.data || []) as FinanceRecurringItem[]);
    setCategories((categoriesRes.data || []) as FinanceCategory[]);
    setLoading(false);
  }, [supabase]);

  useEffect(() => {
    const timer = window.setTimeout(() => {
      void fetchFinances().catch(() => setLoading(false));
    }, 0);

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

  async function createTransaction(input: FinanceTransactionInput) {
    const currentUserId = await requireCurrentUserId();
    const { data, error } = await supabase
      .from("finance_transactions")
      .insert({
        user_id: currentUserId,
        type: input.type,
        title: input.title,
        description: input.description || "",
        category: input.category,
        amount_cents: input.amount_cents,
        currency: input.currency || "EUR",
        transaction_date: input.transaction_date,
        status: input.status || "cleared",
      })
      .select()
      .single();

    if (error) throw error;
    setTransactions((prev) => [data as FinanceTransaction, ...prev]);
    return data as FinanceTransaction;
  }

  async function createTransactions(inputs: FinanceTransactionInput[]) {
    if (inputs.length === 0) return [];
    const currentUserId = await requireCurrentUserId();
    const { data, error } = await supabase
      .from("finance_transactions")
      .insert(
        inputs.map((input) => ({
          user_id: currentUserId,
          type: input.type,
          title: input.title,
          description: input.description || "",
          category: input.category,
          amount_cents: input.amount_cents,
          currency: input.currency || "EUR",
          transaction_date: input.transaction_date,
          status: input.status || "cleared",
        }))
      )
      .select();

    if (error) throw error;
    const next = (data || []) as FinanceTransaction[];
    setTransactions((prev) => [...next, ...prev]);
    return next;
  }

  async function updateTransaction(id: string, input: Partial<FinanceTransactionInput>) {
    const { data, error } = await supabase
      .from("finance_transactions")
      .update(input)
      .eq("id", id)
      .select()
      .single();

    if (error) throw error;
    setTransactions((prev) =>
      prev.map((transaction) => (transaction.id === id ? (data as FinanceTransaction) : transaction))
    );
    return data as FinanceTransaction;
  }

  async function deleteTransaction(id: string) {
    const { error } = await supabase.from("finance_transactions").delete().eq("id", id);
    if (error) throw error;
    setTransactions((prev) => prev.filter((transaction) => transaction.id !== id));
  }

  async function upsertBudget(input: FinanceBudgetInput) {
    const currentUserId = await requireCurrentUserId();
    const { data, error } = await supabase
      .from("finance_budgets")
      .upsert(
        {
          user_id: currentUserId,
          category: input.category,
          amount_cents: input.amount_cents,
          currency: input.currency || "EUR",
          month: input.month,
        },
        { onConflict: "user_id,category,month" }
      )
      .select()
      .single();

    if (error) throw error;
    setBudgets((prev) => {
      const next = data as FinanceBudget;
      const exists = prev.some((budget) => budget.id === next.id);
      if (exists) {
        return prev.map((budget) => (budget.id === next.id ? next : budget));
      }
      return [next, ...prev];
    });
    return data as FinanceBudget;
  }

  async function deleteBudget(id: string) {
    const { error } = await supabase.from("finance_budgets").delete().eq("id", id);
    if (error) throw error;
    setBudgets((prev) => prev.filter((budget) => budget.id !== id));
  }

  async function createRecurringItem(input: FinanceRecurringItemInput) {
    const currentUserId = await requireCurrentUserId();
    const { data, error } = await supabase
      .from("finance_recurring_items")
      .insert({
        user_id: currentUserId,
        type: input.type,
        title: input.title,
        category: input.category,
        amount_cents: input.amount_cents,
        currency: input.currency || "EUR",
        frequency: input.frequency,
        next_due_date: input.next_due_date,
        is_active: input.is_active ?? true,
      })
      .select()
      .single();

    if (error) throw error;
    setRecurringItems((prev) => [data as FinanceRecurringItem, ...prev]);
    return data as FinanceRecurringItem;
  }

  async function updateRecurringItem(
    id: string,
    input: Partial<FinanceRecurringItemInput>
  ) {
    const { data, error } = await supabase
      .from("finance_recurring_items")
      .update(input)
      .eq("id", id)
      .select()
      .single();

    if (error) throw error;
    setRecurringItems((prev) =>
      prev.map((item) => (item.id === id ? (data as FinanceRecurringItem) : item))
    );
    return data as FinanceRecurringItem;
  }

  async function deleteRecurringItem(id: string) {
    const { error } = await supabase.from("finance_recurring_items").delete().eq("id", id);
    if (error) throw error;
    setRecurringItems((prev) => prev.filter((item) => item.id !== id));
  }

  async function createCategory(input: FinanceCategoryInput) {
    const currentUserId = await requireCurrentUserId();
    const { data, error } = await supabase
      .from("finance_categories")
      .insert({
        user_id: currentUserId,
        name: input.name.trim(),
        type: input.type || "both",
        color: input.color || "#6366f1",
        sort_order: input.sort_order ?? categories.length,
      })
      .select()
      .single();

    if (error) throw error;
    setCategories((prev) => [...prev, data as FinanceCategory]);
    return data as FinanceCategory;
  }

  async function updateCategory(id: string, input: Partial<FinanceCategoryInput>) {
    const { data, error } = await supabase
      .from("finance_categories")
      .update(input)
      .eq("id", id)
      .select()
      .single();

    if (error) throw error;
    setCategories((prev) =>
      prev.map((category) => (category.id === id ? (data as FinanceCategory) : category))
    );
    return data as FinanceCategory;
  }

  async function deleteCategory(id: string) {
    const { error } = await supabase.from("finance_categories").delete().eq("id", id);
    if (error) throw error;
    setCategories((prev) => prev.filter((category) => category.id !== id));
  }

  return {
    transactions,
    budgets,
    recurringItems,
    categories,
    loading,
    createTransaction,
    createTransactions,
    updateTransaction,
    deleteTransaction,
    upsertBudget,
    deleteBudget,
    createRecurringItem,
    updateRecurringItem,
    deleteRecurringItem,
    createCategory,
    updateCategory,
    deleteCategory,
    refetch: fetchFinances,
  };
}
