/**
 * PaymentProvider — module-local state for the customer Payments portal.
 *
 * Invoices and transactions are sourced from the shared paymentStore (localStorage)
 * so the customer sees payment requests created on the owner side, and payments
 * made here flow back to the owner's Payment Management page. The server-side
 * (webhook-written) transaction history is merged in on top when available.
 */

import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { stripeConfig } from '../config/stripeConfig';
import {
    loadInvoices,
    loadTransactions,
    saveTransactions,
    subscribe,
} from '../data/paymentStore';

const mergeById = (a, b) => {
    const map = new Map();
    [...a, ...b].forEach((t) => {
        if (t && t.id) map.set(t.id, { ...map.get(t.id), ...t });
    });
    return Array.from(map.values()).sort(
        (x, y) => new Date(y.createdAt || 0) - new Date(x.createdAt || 0)
    );
};

const PaymentContext = createContext(null);

export const PaymentProvider = ({ children }) => {
    const [invoices, setInvoices] = useState(loadInvoices);
    const [transactions, setTransactions] = useState(loadTransactions);

    // Re-read from the shared store whenever the owner adds an invoice, marks
    // one paid, or a payment is recorded (same-tab and cross-tab).
    useEffect(
        () =>
            subscribe(() => {
                setInvoices(loadInvoices());
                setTransactions((prev) => mergeById(prev, loadTransactions()));
            }),
        []
    );

    // Pull the server-side (webhook-written) history and merge it in.
    useEffect(() => {
        let cancelled = false;
        (async () => {
            try {
                const res = await fetch(`${stripeConfig.apiBase}/transactions`);
                if (!res.ok) return;
                const { transactions: server = [] } = await res.json();
                if (cancelled || !server.length) return;
                setTransactions((prev) => mergeById(prev, server));
            } catch {
                /* offline / endpoint unavailable — local history is fine. */
            }
        })();
        return () => {
            cancelled = true;
        };
    }, []);

    /** Record a transaction confirmed on the success return page. */
    const recordTransaction = useCallback((txn) => {
        if (!txn?.id) return;
        setTransactions((prev) => {
            const next = mergeById(prev, [txn]);
            saveTransactions(next); // persists to the shared store + notifies the owner side
            return next;
        });
    }, []);

    const value = { invoices, transactions, recordTransaction };

    return <PaymentContext.Provider value={value}>{children}</PaymentContext.Provider>;
};

export const usePayments = () => {
    const ctx = useContext(PaymentContext);
    if (!ctx) throw new Error('usePayments must be used within a <PaymentProvider>.');
    return ctx;
};
