/**
 * 화면 컨텍스트
 * 같은 화면 내의 컴포넌트들이 서로 통신할 수 있도록 합니다.
 */

"use client";

import React, { createContext, useContext, useCallback, useRef, useState } from "react";
import type { DataProvidable, DataReceivable, DataReceiverConfig } from "@/types/data-transfer";
import { logger } from "@/lib/utils/logger";
import type { SplitPanelPosition } from "@/contexts/SplitPanelContext";

/**
 * 대기 중인 데이터 전달 항목
 * 타겟 컴포넌트가 아직 마운트되지 않은 경우 (조건부 레이어 등) 버퍼에 저장
 */
export interface PendingTransfer {
  targetComponentId: string;
  data: any[];
  config: DataReceiverConfig;
  timestamp: number;
  targetLayerId?: string;
}

interface ScreenContextValue {
  screenId?: number;
  tableName?: string;
  menuObjid?: number;
  splitPanelPosition?: SplitPanelPosition;

  formData: Record<string, any>;
  updateFormData: (fieldName: string, value: any) => void;

  // 컴포넌트 등록
  registerDataProvider: (componentId: string, provider: DataProvidable) => void;
  unregisterDataProvider: (componentId: string) => void;
  registerDataReceiver: (componentId: string, receiver: DataReceivable) => void;
  unregisterDataReceiver: (componentId: string) => void;

  // 컴포넌트 조회
  getDataProvider: (componentId: string) => DataProvidable | undefined;
  getDataReceiver: (componentId: string) => DataReceivable | undefined;

  // 모든 컴포넌트 조회
  getAllDataProviders: () => Map<string, DataProvidable>;
  getAllDataReceivers: () => Map<string, DataReceivable>;

  // 대기 중인 데이터 전달 (레이어 내부 컴포넌트 미마운트 대응)
  addPendingTransfer: (transfer: PendingTransfer) => void;
  getPendingTransfer: (componentId: string) => PendingTransfer | undefined;
  clearPendingTransfer: (componentId: string) => void;
}

const ScreenContext = createContext<ScreenContextValue | null>(null);

interface ScreenContextProviderProps {
  screenId?: number;
  tableName?: string;
  menuObjid?: number; // 메뉴 OBJID
  splitPanelPosition?: SplitPanelPosition; // 🆕 분할 패널 위치
  children: React.ReactNode;
}

/**
 * 화면 컨텍스트 프로바이더
 */
export function ScreenContextProvider({
  screenId,
  tableName,
  menuObjid,
  splitPanelPosition,
  children,
}: ScreenContextProviderProps) {
  const dataProvidersRef = useRef<Map<string, DataProvidable>>(new Map());
  const dataReceiversRef = useRef<Map<string, DataReceivable>>(new Map());
  const pendingTransfersRef = useRef<Map<string, PendingTransfer>>(new Map());

  const [formData, setFormData] = useState<Record<string, any>>({});

  const updateFormData = useCallback((fieldName: string, value: any) => {
    setFormData((prev) => {
      const updated = { ...prev, [fieldName]: value };
      logger.debug("ScreenContext formData 업데이트", {
        fieldName,
        valueType: typeof value,
        isArray: Array.isArray(value),
      });
      return updated;
    });
  }, []);

  const registerDataProvider = useCallback((componentId: string, provider: DataProvidable) => {
    dataProvidersRef.current.set(componentId, provider);
    logger.debug("데이터 제공자 등록", { componentId, componentType: provider.componentType });
  }, []);

  const unregisterDataProvider = useCallback((componentId: string) => {
    dataProvidersRef.current.delete(componentId);
    logger.debug("데이터 제공자 해제", { componentId });
  }, []);

  const registerDataReceiver = useCallback((componentId: string, receiver: DataReceivable) => {
    dataReceiversRef.current.set(componentId, receiver);
    logger.debug("데이터 수신자 등록", { componentId, componentType: receiver.componentType });

    // 대기 중인 데이터 전달이 있으면 즉시 수신 처리
    const pending = pendingTransfersRef.current.get(componentId);
    if (pending) {
      logger.info("대기 중인 데이터 전달 자동 수신", {
        componentId,
        dataCount: pending.data.length,
        waitedMs: Date.now() - pending.timestamp,
      });
      receiver
        .receiveData(pending.data, pending.config)
        .then(() => {
          pendingTransfersRef.current.delete(componentId);
          logger.info("대기 데이터 전달 완료", { componentId });
        })
        .catch((err) => {
          logger.error("대기 데이터 전달 실패", { componentId, error: err });
        });
    }
  }, []);

  const unregisterDataReceiver = useCallback((componentId: string) => {
    dataReceiversRef.current.delete(componentId);
    logger.debug("데이터 수신자 해제", { componentId });
  }, []);

  const getDataProvider = useCallback((componentId: string) => {
    return dataProvidersRef.current.get(componentId);
  }, []);

  const getDataReceiver = useCallback((componentId: string) => {
    return dataReceiversRef.current.get(componentId);
  }, []);

  const getAllDataProviders = useCallback(() => {
    return new Map(dataProvidersRef.current);
  }, []);

  const getAllDataReceivers = useCallback(() => {
    return new Map(dataReceiversRef.current);
  }, []);

  const addPendingTransfer = useCallback((transfer: PendingTransfer) => {
    pendingTransfersRef.current.set(transfer.targetComponentId, transfer);
    logger.info("데이터 전달 대기열 추가", {
      targetComponentId: transfer.targetComponentId,
      dataCount: transfer.data.length,
      targetLayerId: transfer.targetLayerId,
    });
  }, []);

  const getPendingTransfer = useCallback((componentId: string) => {
    return pendingTransfersRef.current.get(componentId);
  }, []);

  const clearPendingTransfer = useCallback((componentId: string) => {
    pendingTransfersRef.current.delete(componentId);
    logger.debug("대기 데이터 전달 클리어", { componentId });
  }, []);

  const value = React.useMemo<ScreenContextValue>(
    () => ({
      screenId,
      tableName,
      menuObjid,
      splitPanelPosition,
      formData,
      updateFormData,
      registerDataProvider,
      unregisterDataProvider,
      registerDataReceiver,
      unregisterDataReceiver,
      getDataProvider,
      getDataReceiver,
      getAllDataProviders,
      getAllDataReceivers,
      addPendingTransfer,
      getPendingTransfer,
      clearPendingTransfer,
    }),
    [
      screenId,
      tableName,
      menuObjid,
      splitPanelPosition,
      formData,
      updateFormData,
      registerDataProvider,
      unregisterDataProvider,
      registerDataReceiver,
      unregisterDataReceiver,
      getDataProvider,
      getDataReceiver,
      getAllDataProviders,
      getAllDataReceivers,
      addPendingTransfer,
      getPendingTransfer,
      clearPendingTransfer,
    ],
  );

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

/**
 * 화면 컨텍스트 훅
 */
export function useScreenContext() {
  const context = useContext(ScreenContext);
  if (!context) {
    throw new Error("useScreenContext는 ScreenContextProvider 내부에서만 사용할 수 있습니다.");
  }
  return context;
}

/**
 * 화면 컨텍스트 훅 (선택적)
 * 컨텍스트가 없어도 에러를 발생시키지 않습니다.
 */
export function useScreenContextOptional() {
  return useContext(ScreenContext);
}
