import { createContext, useContext, useState, useCallback, type ReactNode } from "react";
import {
  usePeriodicExpenses,
  useCreatePeriodicExpense,
  useUpdatePeriodicExpense,
  useDeletePeriodicExpense,
  useGenerateMonthlyExpense,
  useExpenses,
  useCreateNonPeriodicExpense,
  usePayExpense,
  useMonthlyTotals,
} from "@/lib/queries";
import type {
  PeriodicExpense,
  Expense,
  CreatePeriodicExpenseInput,
  CreateNonPeriodicExpenseInput,
  PayExpenseInput,
  PaginatedResponse,
  MonthlyTotals,
} from "@/lib/api";

interface ExpensesContextValue {
  periodicExpenses: PeriodicExpense[];
  isLoadingPeriodic: boolean;

  expenses: PaginatedResponse<Expense>;
  isLoadingExpenses: boolean;
  statusFilter: string;
  setStatusFilter: (status: string) => void;
  page: number;
  setPage: (page: number) => void;
  pageSize: number;

  monthlyTotals: MonthlyTotals | undefined;
  isLoadingTotals: boolean;

  createPeriodicExpense: (data: CreatePeriodicExpenseInput) => Promise<PeriodicExpense>;
  updatePeriodicExpense: (id: number, data: CreatePeriodicExpenseInput) => Promise<void>;
  deletePeriodicExpense: (id: number) => Promise<void>;
  generateMonthlyExpense: (id: number) => Promise<Expense>;
  createNonPeriodicExpense: (data: CreateNonPeriodicExpenseInput) => Promise<void>;
  payExpense: (id: number, data: PayExpenseInput) => Promise<void>;
}

const ExpensesContext = createContext<ExpensesContextValue | null>(null);

export function ExpensesProvider({ children }: { children: ReactNode }) {
  const [statusFilter, setStatusFilter] = useState("PENDING");
  const [page, setPage] = useState(1);
  const pageSize = 10;

  const { data: periodicExpenses = [], isLoading: isLoadingPeriodic } = usePeriodicExpenses();
  const { data: expenses = { data: [], total: 0, page: 1, pageSize: 10 }, isLoading: isLoadingExpenses } =
    useExpenses(statusFilter, page, pageSize);

  const now = new Date();
  const { data: monthlyTotals, isLoading: isLoadingTotals } = useMonthlyTotals(now.getFullYear(), now.getMonth() + 1);

  const createPeriodicMutation = useCreatePeriodicExpense();
  const updatePeriodicMutation = useUpdatePeriodicExpense();
  const deletePeriodicMutation = useDeletePeriodicExpense();
  const generateMonthlyMutation = useGenerateMonthlyExpense();
  const createExpenseMutation = useCreateNonPeriodicExpense();
  const payExpenseMutation = usePayExpense();

  const createPeriodicExpense = useCallback(
    async (data: CreatePeriodicExpenseInput): Promise<PeriodicExpense> => {
      return createPeriodicMutation.mutateAsync(data);
    },
    [createPeriodicMutation],
  );

  const updatePeriodicExpenseFn = useCallback(
    async (id: number, data: CreatePeriodicExpenseInput) => {
      await updatePeriodicMutation.mutateAsync({ id, data });
    },
    [updatePeriodicMutation],
  );

  const deletePeriodicExpenseFn = useCallback(
    async (id: number) => {
      await deletePeriodicMutation.mutateAsync(id);
    },
    [deletePeriodicMutation],
  );

  const generateMonthlyExpenseFn = useCallback(
    async (id: number): Promise<Expense> => {
      return generateMonthlyMutation.mutateAsync(id);
    },
    [generateMonthlyMutation],
  );

  const createNonPeriodicExpenseFn = useCallback(
    async (data: CreateNonPeriodicExpenseInput) => {
      await createExpenseMutation.mutateAsync(data);
    },
    [createExpenseMutation],
  );

  const payExpenseFn = useCallback(
    async (id: number, data: PayExpenseInput) => {
      await payExpenseMutation.mutateAsync({ id, data });
    },
    [payExpenseMutation],
  );

  return (
    <ExpensesContext
      value={{
        periodicExpenses,
        isLoadingPeriodic,
        expenses,
        isLoadingExpenses,
        statusFilter,
        setStatusFilter,
        page,
        setPage,
        pageSize,
        monthlyTotals,
        isLoadingTotals,
        createPeriodicExpense,
        updatePeriodicExpense: updatePeriodicExpenseFn,
        deletePeriodicExpense: deletePeriodicExpenseFn,
        generateMonthlyExpense: generateMonthlyExpenseFn,
        createNonPeriodicExpense: createNonPeriodicExpenseFn,
        payExpense: payExpenseFn,
      }}
    >
      {children}
    </ExpensesContext>
  );
}

export function useExpensesContext() {
  const ctx = useContext(ExpensesContext);
  if (!ctx) throw new Error("useExpensesContext must be used within ExpensesProvider");
  return ctx;
}
