"use client";

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

import React, { useState, useEffect, useCallback, useRef } from "react";
import type { PopDashboardConfig, DashboardItem, DashboardPage } 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";

// ===== 마이그레이션: 기존 config -> 페이지 기반 구조 변환 =====

/**
 * 기존 config를 페이지 기반 구조로 마이그레이션.
 * 런타임에서만 사용 (저장된 config 원본은 변경하지 않음).
 *
 * 시나리오1: displayMode="grid" (가장 오래된 형태)
 * 시나리오2: useGridLayout=true (직전 마이그레이션 결과)
 * 시나리오3: pages 이미 있음 (새 형태) -> 변환 불필요
 * 시나리오4: pages 없음 + grid 아님 -> 빈 pages (아이템 하나씩 슬라이드)
 */
export function migrateConfig(raw: Record<string, unknown>): PopDashboardConfig {
  const config = { ...raw } as PopDashboardConfig & Record<string, unknown>;

  // pages가 이미 있으면 마이그레이션 불필요
  if (Array.isArray(config.pages) && config.pages.length > 0) {
    return config;
  }

  // 시나리오1: displayMode="grid" / 시나리오2: useGridLayout=true
  const wasGrid =
    config.displayMode === ("grid" as string) || (config as Record<string, unknown>).useGridLayout === true;

  if (wasGrid) {
    const cols = ((config as Record<string, unknown>).gridColumns as number) ?? 2;
    const rows = ((config as Record<string, unknown>).gridRows as number) ?? 2;
    const cells = ((config as Record<string, unknown>).gridCells as DashboardPage["gridCells"]) ?? [];

    const page: DashboardPage = {
      id: "migrated-page-1",
      label: "페이지 1",
      gridColumns: cols,
      gridRows: rows,
      gridCells: cells,
    };

    config.pages = [page];

    // displayMode="grid" 보정
    if (config.displayMode === ("grid" as string)) {
      (config as Record<string, unknown>).displayMode = "arrows";
    }
  }

  return config as PopDashboardConfig;
}

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

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,
  previewPageIndex,
}: {
  config?: PopDashboardConfig;
  /** 디자이너 페이지 미리보기: 이 인덱스의 페이지만 단독 렌더링 (-1이면 기본 모드) */
  previewPageIndex?: number;
}) {
  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);

  // 보이는 아이템만 필터링 (hooks 이전에 early return 불가하므로 빈 배열 허용)
  const visibleItems = Array.isArray(config?.items) ? 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();
  }, []);

  // 아이템 ID 목록 문자열 키 (참조 안정성 보장 - 매 렌더마다 새 배열 참조 방지)
  const visibleItemIds = JSON.stringify(visibleItems.map((i) => i.id));

  // 데이터 로딩 함수
  // eslint-disable-next-line react-hooks/exhaustive-deps
  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);
  }, [visibleItemIds]);

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

    // refreshInterval 적용 (첫 번째 아이템 기준, 최소 5초 강제)
    const rawRefreshSec = visibleItems[0]?.dataSource.refreshInterval;
    const refreshSec = rawRefreshSec && rawRefreshSec > 0 ? Math.max(5, rawRefreshSec) : 0;
    if (refreshSec > 0) {
      refreshTimerRef.current = setInterval(fetchAllData, refreshSec * 1000);
    }

    return () => {
      if (refreshTimerRef.current) {
        clearInterval(refreshTimerRef.current);
        refreshTimerRef.current = null;
      }
    };
    // visibleItemIds로 아이템 변경 감지 (visibleItems 객체 참조 대신 문자열 키 사용)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fetchAllData, visibleItemIds]);

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

  // 단일 아이템 렌더링
  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-muted-foreground text-xs">로딩 중...</span>
        </div>
      );
    }

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

    switch (item.subType) {
      case "kpi-card":
        return <KpiCardComponent item={item} data={itemData.value} formulaDisplay={itemData.formulaDisplay} />;
      case "chart": {
        // groupBy가 있지만 xAxisColumn이 미설정이면 자동 보정
        const chartItem = { ...item };
        if (item.dataSource.aggregation?.groupBy?.length && !item.chartConfig?.xAxisColumn) {
          chartItem.chartConfig = {
            ...chartItem.chartConfig,
            chartType: chartItem.chartConfig?.chartType ?? "bar",
            xAxisColumn: item.dataSource.aggregation.groupBy[0],
          };
        }
        return <ChartItemComponent item={chartItem} 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) {
            if (cat.filter.column && cat.filter.value !== undefined && cat.filter.value !== "") {
              // 카테고리 필터로 rows 필터링
              const filtered = itemData.rows.filter((row) => {
                const cellValue = String(row[cat.filter.column] ?? "");
                const filterValue = String(cat.filter.value ?? "");
                switch (cat.filter.operator) {
                  case "=":
                    return cellValue === filterValue;
                  case "!=":
                    return cellValue !== filterValue;
                  case "like":
                    return cellValue.toLowerCase().includes(filterValue.toLowerCase());
                  default:
                    return cellValue === filterValue;
                }
              });
              categoryData[cat.label] = filtered.length;
            } else {
              // 필터 미설정 시 전체 건수
              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-muted-foreground text-xs">미지원 타입: {item.subType}</span>
          </div>
        );
    }
  };

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

  // 마이그레이션: 기존 config를 페이지 기반으로 변환
  const migrated = migrateConfig(config as unknown as Record<string, unknown>);
  const pages = migrated.pages ?? [];
  const displayMode = migrated.displayMode;

  // 페이지 하나를 GridModeComponent로 렌더링
  const renderPageContent = (page: DashboardPage) => {
    return (
      <GridModeComponent
        cells={page.gridCells}
        columns={page.gridColumns}
        rows={page.gridRows}
        gap={config.gap}
        containerWidth={containerWidth}
        renderItem={(itemId) => {
          const item = visibleItems.find((i) => i.id === itemId);
          if (!item) return null;
          return renderSingleItem(item);
        }}
      />
    );
  };

  // 슬라이드 수: pages가 있으면 페이지 수, 없으면 아이템 수 (기존 동작)
  const slideCount = pages.length > 0 ? pages.length : visibleItems.length;

  // 슬라이드 렌더 콜백: pages가 있으면 페이지 렌더, 없으면 단일 아이템
  const renderSlide = (index: number) => {
    if (pages.length > 0 && pages[index]) {
      return renderPageContent(pages[index]);
    }
    // fallback: 아이템 하나씩 (기존 동작 - pages 미설정 시)
    if (visibleItems[index]) {
      return renderSingleItem(visibleItems[index]);
    }
    return null;
  };

  // 페이지 미리보기 모드: 특정 페이지만 단독 렌더링 (디자이너에서 사용)
  if (typeof previewPageIndex === "number" && previewPageIndex >= 0 && pages[previewPageIndex]) {
    return (
      <div
        ref={containerRef}
        className="h-full w-full"
        style={config.backgroundColor ? { backgroundColor: config.backgroundColor } : undefined}
      >
        {renderPageContent(pages[previewPageIndex])}
      </div>
    );
  }

  // 표시 모드별 렌더링
  return (
    <div
      ref={containerRef}
      className="h-full w-full"
      style={config.backgroundColor ? { backgroundColor: config.backgroundColor } : undefined}
    >
      {displayMode === "arrows" && (
        <ArrowsModeComponent itemCount={slideCount} showIndicator={config.showIndicator} renderItem={renderSlide} />
      )}

      {displayMode === "auto-slide" && (
        <AutoSlideModeComponent
          itemCount={slideCount}
          interval={config.autoSlideInterval}
          resumeDelay={config.autoSlideResumeDelay}
          showIndicator={config.showIndicator}
          renderItem={renderSlide}
        />
      )}

      {displayMode === "scroll" && (
        <ScrollModeComponent itemCount={slideCount} showIndicator={config.showIndicator} renderItem={renderSlide} />
      )}
    </div>
  );
}
