"use client";

import {
  createContext,
  useCallback,
  useContext,
  useMemo,
  useSyncExternalStore,
  type ReactNode,
} from "react";
import {
  type CurrencyCode,
  convertFromUsd,
  formatMoneyFromUsd,
  isCurrencyCode,
} from "@/lib/currency";

const STORAGE_KEY = "shitaye-currency";
const CURRENCY_EVENT = "shitaye-currency-change";

type CurrencyContextValue = {
  currency: CurrencyCode;
  setCurrency: (c: CurrencyCode) => void;
  formatUsd: (amountUsd: number, maximumFractionDigits?: 0 | 1 | 2) => string;
  convertUsd: (amountUsd: number) => number;
};

const CurrencyContext = createContext<CurrencyContextValue | null>(null);

function readCurrency(): CurrencyCode {
  if (typeof window === "undefined") return "USD";
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw && isCurrencyCode(raw)) return raw;
  } catch {
    /* ignore */
  }
  return "USD";
}

function subscribe(onChange: () => void) {
  if (typeof window === "undefined") return () => {};
  const handler = () => onChange();
  window.addEventListener("storage", handler);
  window.addEventListener(CURRENCY_EVENT, handler);
  return () => {
    window.removeEventListener("storage", handler);
    window.removeEventListener(CURRENCY_EVENT, handler);
  };
}

export function CurrencyProvider({ children }: { children: ReactNode }) {
  const currency = useSyncExternalStore(
    subscribe,
    readCurrency,
    () => "USD" as CurrencyCode,
  ) as CurrencyCode;

  const setCurrency = useCallback((c: CurrencyCode) => {
    try {
      localStorage.setItem(STORAGE_KEY, c);
      window.dispatchEvent(new Event(CURRENCY_EVENT));
    } catch {
      /* ignore */
    }
  }, []);

  const value = useMemo((): CurrencyContextValue => {
    return {
      currency,
      setCurrency,
      formatUsd: (amountUsd, maximumFractionDigits = 2) =>
        formatMoneyFromUsd(amountUsd, currency, maximumFractionDigits),
      convertUsd: (amountUsd) => convertFromUsd(amountUsd, currency),
    };
  }, [currency, setCurrency]);

  return (
    <CurrencyContext.Provider value={value}>{children}</CurrencyContext.Provider>
  );
}

export function useCurrency() {
  const ctx = useContext(CurrencyContext);
  if (!ctx) throw new Error("useCurrency must be used within CurrencyProvider");
  return ctx;
}
