"use client";

/**
 * pop-dashboard 메인 컴포넌트 (뷰어용)
 *
 * 멀티 아이템 컨테이너: 여러 집계 아이템을 묶어서 다양한 표시 모드로 렌더링
 *
 * @INFRA-EXTRACT 대상:
 * - fetchAggregatedData 호출부 -> useDataSource로 교체 예정
 * - filter_changed 이벤트 수신 -> usePopEvent로 교체 예정
 */

import React, { useState, useEffect, useCallback, useRef } from "react";
import type {
  PopDashboardConfig,
  DashboardItem,
} from "../types";
import { fetchAggregatedData } from "./utils/dataFetcher";
import {
  evaluateFormula,
  formatFormulaResult,
} from "./utils/formula";

// 서브타입 아이템 컴포넌트
import { KpiCardComponent } from "./items/KpiCard";
import { ChartItemComponent } from "./items/ChartItem";
import { GaugeItemComponent } from "./items/GaugeItem";
import { StatCardComponent } from "./items/StatCard";

// 표시 모드 컴포넌트
import { ArrowsModeComponent } from "./modes/ArrowsMode";
import { AutoSlideModeComponent } from "./modes/AutoSlideMode";
import { GridModeComponent } from "./modes/GridMode";
import { ScrollModeComponent } from "./modes/ScrollMode";

// ===== 내부 타입 =====

interface ItemData {
  /** 단일 집계 값 */
  value: number;
  /** 데이터 행 (차트용) */
  rows: Record<string, unknown>[];
  /** 수식 결과 표시 문자열 */
  formulaDisplay: string | null;
  /** 에러 메시지 */
  error: string | null;
}

// ===== 데이터 로딩 함수 =====

/** 단일 아이템의 데이터를 조회 */
async function loadItemData(item: DashboardItem): Promise<ItemData> {
  try {
    // 수식 모드
    if (item.formula?.enabled && item.formula.values.length > 0) {
      // 각 값(A, B, ...)을 병렬 조회
      const results = await Promise.allSettled(
        item.formula.values.map((fv) => fetchAggregatedData(fv.dataSource))
      );

      const valueMap: Record<string, number> = {};
      for (let i = 0; i < item.formula.values.length; i++) {
        const result = results[i];
        const fv = item.formula.values[i];
        valueMap[fv.id] =
          result.status === "fulfilled" ? result.value.value : 0;
      }

      const calculatedValue = evaluateFormula(
        item.formula.expression,
        valueMap
      );
      const formulaDisplay = formatFormulaResult(item.formula, valueMap);

      return {
        value: calculatedValue,
        rows: [],
        formulaDisplay,
        error: null,
      };
    }

    // 단일 집계 모드
    const result = await fetchAggregatedData(item.dataSource);
    if (result.error) {
      return { value: 0, rows: [], formulaDisplay: null, error: result.error };
    }

    return {
      value: result.value,
      rows: result.rows ?? [],
      formulaDisplay: null,
      error: null,
    };
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "데이터 로딩 실패";
    return { value: 0, rows: [], formulaDisplay: null, error: message };
  }
}

// ===== 메인 컴포넌트 =====

export function PopDashboardComponent({
  config,
}: {
  config?: PopDashboardConfig;
}) {
  const [dataMap, setDataMap] = useState<Record<string, ItemData>>({});
  const [loading, setLoading] = useState(true);
  const refreshTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const [containerWidth, setContainerWidth] = useState(300);

  // 빈 설정
  if (!config || !config.items.length) {
    return (
      <div className="flex h-full w-full items-center justify-center bg-muted/20">
        <span className="text-sm text-muted-foreground">
          대시보드 아이템을 추가하세요
        </span>
      </div>
    );
  }

  // 보이는 아이템만 필터링
  const visibleItems = config.items.filter((item) => item.visible);

  // 컨테이너 크기 감지
  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;

    const observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        setContainerWidth(entry.contentRect.width);
      }
    });
    observer.observe(el);
    return () => observer.disconnect();
  }, []);

  // 데이터 로딩 함수
  const fetchAllData = useCallback(async () => {
    if (!visibleItems.length) {
      setLoading(false);
      return;
    }

    setLoading(true);

    // 모든 아이템 병렬 로딩 (하나 실패해도 나머지 표시)
    // @INFRA-EXTRACT: useDataSource로 교체 예정
    const results = await Promise.allSettled(
      visibleItems.map((item) => loadItemData(item))
    );

    const newDataMap: Record<string, ItemData> = {};
    for (let i = 0; i < visibleItems.length; i++) {
      const result = results[i];
      newDataMap[visibleItems[i].id] =
        result.status === "fulfilled"
          ? result.value
          : { value: 0, rows: [], formulaDisplay: null, error: "로딩 실패" };
    }

    setDataMap(newDataMap);
    setLoading(false);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [JSON.stringify(visibleItems.map((i) => i.id))]);

  // 초기 로딩 + 주기적 새로고침
  useEffect(() => {
    fetchAllData();

    // refreshInterval 적용 (첫 번째 아이템 기준)
    const refreshSec = visibleItems[0]?.dataSource.refreshInterval;
    if (refreshSec && refreshSec > 0) {
      refreshTimerRef.current = setInterval(fetchAllData, refreshSec * 1000);
    }

    return () => {
      if (refreshTimerRef.current) {
        clearInterval(refreshTimerRef.current);
        refreshTimerRef.current = null;
      }
    };
  }, [fetchAllData, visibleItems]);

  // 단일 아이템 렌더링
  const renderSingleItem = (item: DashboardItem) => {
    const itemData = dataMap[item.id];
    if (!itemData) {
      return (
        <div className="flex h-full w-full items-center justify-center">
          <span className="text-xs text-muted-foreground">로딩 중...</span>
        </div>
      );
    }

    if (itemData.error) {
      return (
        <div className="flex h-full w-full items-center justify-center">
          <span className="text-xs text-destructive">{itemData.error}</span>
        </div>
      );
    }

    switch (item.subType) {
      case "kpi-card":
        return (
          <KpiCardComponent
            item={item}
            data={itemData.value}
            formulaDisplay={itemData.formulaDisplay}
          />
        );
      case "chart":
        return (
          <ChartItemComponent
            item={item}
            rows={itemData.rows}
            containerWidth={containerWidth}
          />
        );
      case "gauge":
        return <GaugeItemComponent item={item} data={itemData.value} />;
      case "stat-card": {
        // StatCard: 카테고리별 건수 맵 구성
        const categoryData: Record<string, number> = {};
        if (item.statConfig?.categories) {
          for (const cat of item.statConfig.categories) {
            // 각 카테고리 행에서 건수 추출 (간단 구현: 행 수 기준)
            categoryData[cat.label] = itemData.rows.length;
          }
        }
        return (
          <StatCardComponent item={item} categoryData={categoryData} />
        );
      }
      default:
        return (
          <div className="flex h-full w-full items-center justify-center">
            <span className="text-xs text-muted-foreground">
              미지원 타입: {item.subType}
            </span>
          </div>
        );
    }
  };

  // 로딩 상태
  if (loading && !Object.keys(dataMap).length) {
    return (
      <div className="flex h-full w-full items-center justify-center">
        <div className="h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" />
      </div>
    );
  }

  // 표시 모드별 렌더링
  const displayMode = config.displayMode;

  return (
    <div
      ref={containerRef}
      className="h-full w-full"
      style={
        config.backgroundColor
          ? { backgroundColor: config.backgroundColor }
          : undefined
      }
    >
      {displayMode === "arrows" && (
        <ArrowsModeComponent
          itemCount={visibleItems.length}
          showIndicator={config.showIndicator}
          renderItem={(index) => renderSingleItem(visibleItems[index])}
        />
      )}

      {displayMode === "auto-slide" && (
        <AutoSlideModeComponent
          itemCount={visibleItems.length}
          interval={config.autoSlideInterval}
          resumeDelay={config.autoSlideResumeDelay}
          showIndicator={config.showIndicator}
          renderItem={(index) => renderSingleItem(visibleItems[index])}
        />
      )}

      {displayMode === "grid" && (
        <GridModeComponent
          cells={config.gridCells ?? []}
          columns={config.gridColumns ?? 2}
          rows={config.gridRows ?? 2}
          gap={config.gap}
          renderItem={(itemId) => {
            const item = visibleItems.find((i) => i.id === itemId);
            if (!item) return null;
            return renderSingleItem(item);
          }}
        />
      )}

      {displayMode === "scroll" && (
        <ScrollModeComponent
          itemCount={visibleItems.length}
          showIndicator={config.showIndicator}
          renderItem={(index) => renderSingleItem(visibleItems[index])}
        />
      )}
    </div>
  );
}
