/* Company Stock Price — market store: live API only, paginated stock loading. */
const REFRESH_MS = (window.FinnhubSymbols && window.FinnhubSymbols.REFRESH_MS) || 5 * 60 * 1000;

const MarketDataCtx = React.createContext(null);
function useMarketData() { return React.useContext(MarketDataCtx); }

function mergeStocks(existing, incoming) {
  const map = new Map((existing || []).map((s) => [s.symbol || s.ticker, s]));
  (incoming || []).forEach((s) => map.set(s.symbol || s.ticker, s));
  return [...map.values()];
}

function MarketDataProvider({ children }) {
  const L = useLive();
  const [state, setState] = useState({
    loading: false,
    ready: false,
    stocks: [],
    stocksTotal: 0,
    stocksHasMore: false,
    stocksLoadingMore: false,
    stockPageSize: 15,
    indices: [],
    globalIndices: [],
    globalStocks: [],
    globalLoading: false,
    news: [],
    status: null,
    error: null,
    lastUpdated: null,
  });

  const loadRemainingStocks = React.useCallback(async (startOffset, pageSize, opts = {}) => {
    let offset = startOffset;
    let hasMore = true;
    let merged = [];
    while (hasMore) {
      const page = await L.market.getIndiaStocksPage({ offset, limit: pageSize, ...opts });
      merged = mergeStocks(merged, page.stocks);
      setState((s) => ({
        ...s,
        stocks: mergeStocks(s.stocks, page.stocks),
        stocksHasMore: page.hasMore,
        stocksTotal: page.total,
      }));
      hasMore = page.hasMore;
      offset += pageSize;
    }
    return merged;
  }, [L.market]);

  const loadIndia = React.useCallback(async (opts = {}) => {
    setState((s) => ({ ...s, loading: !s.ready, error: null }));
    try {
      const overview = await L.market.getIndiaOverview(opts);
      const pageSize = overview.stockPageSize || 15;
      setState((s) => ({
        loading: false,
        ready: true,
        stocks: overview.stocks,
        stocksTotal: overview.stocksTotal,
        stocksHasMore: overview.stocksHasMore,
        stocksLoadingMore: overview.stocksHasMore,
        stockPageSize: pageSize,
        indices: overview.indices,
        globalIndices: s.globalIndices,
        globalStocks: s.globalStocks,
        globalLoading: false,
        news: (() => {
          if (window.NewsCache && overview.news) window.NewsCache.putMany(overview.news);
          return overview.news;
        })(),
        funds: [],
        status: overview.status,
        error: null,
        lastUpdated: Date.now(),
      }));
      if (overview.stocksHasMore) {
        await loadRemainingStocks(pageSize, pageSize, opts);
        setState((s) => ({ ...s, stocksLoadingMore: false }));
      }
    } catch (e) {
      setState((s) => ({
        ...s,
        loading: false,
        ready: false,
        stocksLoadingMore: false,
        error: apiErrorMessage(e),
      }));
    }
  }, [L.market, loadRemainingStocks]);

  const loadMoreStocks = React.useCallback(async () => {
    if (state.stocksLoadingMore || !state.stocksHasMore) return;
    setState((s) => ({ ...s, stocksLoadingMore: true }));
    try {
      const page = await L.market.getIndiaStocksPage({
        offset: state.stocks.length,
        limit: state.stockPageSize,
      });
      setState((s) => ({
        ...s,
        stocks: mergeStocks(s.stocks, page.stocks),
        stocksHasMore: page.hasMore,
        stocksTotal: page.total,
        stocksLoadingMore: false,
      }));
    } catch (e) {
      setState((s) => ({ ...s, stocksLoadingMore: false }));
    }
  }, [L.market, state.stocks.length, state.stocksHasMore, state.stocksLoadingMore, state.stockPageSize]);

  const loadGlobal = React.useCallback(async () => {
    if (!L.hasKey) return;
    setState((s) => ({ ...s, globalLoading: true }));
    try {
      const [globalIndices, globalStocks] = await Promise.all([
        L.market.getGlobalIndices(),
        L.market.getGlobalStocks(L.market.globalWatchlist()),
      ]);
      L.refreshRateLimit();
      setState((s) => ({
        ...s,
        globalIndices,
        globalStocks,
        globalLoading: false,
      }));
    } catch (e) {
      setState((s) => ({ ...s, globalLoading: false }));
    }
  }, [L]);

  const load = React.useCallback((opts) => loadIndia(opts), [loadIndia]);

  useEffect(() => {
    loadIndia();
    const id = setInterval(() => loadIndia({ noCache: true }), REFRESH_MS);
    return () => clearInterval(id);
  }, [loadIndia]);

  useEffect(() => {
    if (!L.hasKey) return;
    const id = setInterval(() => {
      if (state.globalIndices.length) loadGlobal();
    }, REFRESH_MS);
    return () => clearInterval(id);
  }, [L.hasKey, state.globalIndices.length, loadGlobal]);

  const value = {
    ...state,
    reload: load,
    loadGlobal,
    loadMoreStocks,
    refreshMs: REFRESH_MS,
    indexMeta: Object.fromEntries(
      (state.indices || []).map((ix) => [ix.label, {
        desc: ix.desc,
        members: (window.FinnhubSymbols.IN.INDEX_MEMBERS[ix.label] || []),
      }])
    ),
    globalIndexMeta: Object.fromEntries(
      (state.globalIndices || []).map((ix) => [ix.label, {
        desc: ix.desc,
        members: (window.FinnhubSymbols.US.INDEX_MEMBERS[ix.label] || []),
      }])
    ),
    indexMembers: (label, region = 'IN') => {
      const map = region === 'US'
        ? window.FinnhubSymbols.US.INDEX_MEMBERS
        : window.FinnhubSymbols.IN.INDEX_MEMBERS;
      const syms = map[label];
      if (!syms) return [];
      const pool = region === 'US' ? state.globalStocks : state.stocks;
      return pool.filter((s) => syms.includes(s.symbol || (s.ticker + '.NS')));
    },
  };

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

Object.assign(window, { MarketDataCtx, useMarketData, MarketDataProvider });
