"use client";

import React, { createContext, useContext, useState, useCallback } from "react";
import type { IFunnelPaymentPlacement } from "../funnel/types";
import { loadFunnelPaymentById } from "../funnel/loaders";

interface PlacementCacheEntry {
  placement: IFunnelPaymentPlacement | null;
  isLoading: boolean;
  error: string | null;
}

interface PaymentPlacementContextValue {
  getPlacement: (
    funnelKey: string,
    paymentId: string
  ) => PlacementCacheEntry;
  loadPlacement: (funnelKey: string, paymentId: string) => Promise<void>;
}

const PaymentPlacementContext = createContext<PaymentPlacementContextValue | null>(
  null
);

type PreloadedPlacement = {
  funnelKey: string;
  paymentId: string;
  placement: IFunnelPaymentPlacement;
};

export function PaymentPlacementProvider({
  children,
  initialCache,
}: {
  children: React.ReactNode;
  initialCache?: PreloadedPlacement[];
}) {
  // Cache: Map<"funnelKey:paymentId", PlacementCacheEntry>
  const [cache, setCache] = useState<Map<string, PlacementCacheEntry>>(() => {
    const map = new Map<string, PlacementCacheEntry>();
    initialCache?.forEach(({ funnelKey, paymentId, placement }) => {
      const key = `${funnelKey}:${paymentId}`;
      map.set(key, { placement, isLoading: false, error: null });
    });
    return map;
  });

  const getCacheKey = (funnelKey: string, paymentId: string) =>
    `${funnelKey}:${paymentId}`;

  const getPlacement = useCallback(
    (funnelKey: string, paymentId: string): PlacementCacheEntry => {
      const key = getCacheKey(funnelKey, paymentId);
      return (
        cache.get(key) || { placement: null, isLoading: false, error: null }
      );
    },
    [cache]
  );

  const loadPlacement = useCallback(
    async (funnelKey: string, paymentId: string) => {
      const key = getCacheKey(funnelKey, paymentId);

      // Если уже загружается или загружено, не делаем повторный запрос
      const existing = cache.get(key);
      if (existing?.isLoading || existing?.placement) {
        return;
      }

      // Отмечаем как загружающийся
      setCache((prev) => {
        const next = new Map(prev);
        next.set(key, { placement: null, isLoading: true, error: null });
        return next;
      });

      try {
        const data = await loadFunnelPaymentById(
          { funnel: funnelKey },
          paymentId
        );

        // Normalize union: record value can be IFunnelPaymentPlacement or IFunnelPaymentPlacement[] or null
        const normalized: IFunnelPaymentPlacement | null = Array.isArray(data)
          ? data[0] ?? null
          : data ?? null;

        setCache((prev) => {
          const next = new Map(prev);
          next.set(key, { placement: normalized, isLoading: false, error: null });
          return next;
        });
      } catch (e) {
        const message =
          e instanceof Error ? e.message : "Failed to load payment placement";
        setCache((prev) => {
          const next = new Map(prev);
          next.set(key, { placement: null, isLoading: false, error: message });
          return next;
        });
      }
    },
    [cache]
  );

  return (
    <PaymentPlacementContext.Provider value={{ getPlacement, loadPlacement }}>
      {children}
    </PaymentPlacementContext.Provider>
  );
}

export function usePaymentPlacementContext() {
  const context = useContext(PaymentPlacementContext);
  if (!context) {
    throw new Error(
      "usePaymentPlacementContext must be used within PaymentPlacementProvider"
    );
  }
  return context;
}
