"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";
import type { Transaction } from "@/types";
import { MOCK_TRANSACTIONS } from "@/data/mockTransactions";
import { delay, generateId, generateReference } from "@/lib/mockApi";

const STORAGE_KEY = "xremit_transactions";

export type NewTransactionInput = Omit<
  Transaction,
  "id" | "reference" | "createdAt" | "timeline" | "status"
> & {
  status?: Transaction["status"];
};

interface TransactionsContextValue {
  transactions: Transaction[];
  hydrated: boolean;
  loading: boolean;
  getById: (id: string) => Transaction | undefined;
  add: (input: NewTransactionInput) => Promise<Transaction>;
}

const TransactionsContext = createContext<TransactionsContextValue | undefined>(undefined);

function read(): Transaction[] {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw) return JSON.parse(raw) as Transaction[];
    localStorage.setItem(STORAGE_KEY, JSON.stringify(MOCK_TRANSACTIONS));
    return MOCK_TRANSACTIONS;
  } catch {
    return MOCK_TRANSACTIONS;
  }
}

function persist(list: Transaction[]) {
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(list));
  } catch {
    /* ignore */
  }
}

export function TransactionsProvider({ children }: { children: React.ReactNode }) {
  const [transactions, setTransactions] = useState<Transaction[]>([]);
  const [hydrated, setHydrated] = useState(false);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setTransactions(read());
    setHydrated(true);
  }, []);

  const getById = useCallback(
    (id: string) => transactions.find((t) => t.id === id),
    [transactions],
  );

  const add = useCallback(async (input: NewTransactionInput): Promise<Transaction> => {
    setLoading(true);
    await delay();
    const now = new Date().toISOString();
    const status = input.status ?? "pending";
    const next: Transaction = {
      ...input,
      id: generateId("txn"),
      reference: generateReference(),
      status,
      timeline: [{ status, at: now }],
      createdAt: now,
    };
    setTransactions((prev) => {
      const list = [next, ...prev];
      persist(list);
      return list;
    });
    setLoading(false);
    return next;
  }, []);

  const value = useMemo<TransactionsContextValue>(
    () => ({ transactions, hydrated, loading, getById, add }),
    [transactions, hydrated, loading, getById, add],
  );

  return <TransactionsContext.Provider value={value}>{children}</TransactionsContext.Provider>;
}

export function useTransactions() {
  const ctx = useContext(TransactionsContext);
  if (!ctx) throw new Error("useTransactions must be used within TransactionsProvider");
  return ctx;
}
