"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { aggregateTableGroup, type AggregateGroupRow } from "@/lib/api/stats";
import type { OptionFilter } from "@/lib/registry/components/input/use-option-loader";
import type { ChartDataSource } from "./types";

/**
 * use-chart-data — Phase G.3
 *
 * canonical chart 의 `dataSource` 가 채워져 있으면 `/aggregate-group` endpoint 를
 * 호출해 그룹별 집계 row 배열을 반환한다.
 *
 *   - 디자인 모드: fetch 0건. preview rows 로 fallback
 *   - request key 캐시 (같은 호출 중복 발생 안함)
 *   - version counter race guard
 *   - 실패 시 throw 안 하고 error state 로 반환 — 컴포넌트가 fallback 표시
 *
 * use-stats-data 와 같은 패턴 (StatsItem 단위 → 차트 단위 한 개) 으로 구현.
 */

export interface UseChartDataOptions {
  isDesignMode?: boolean;
  formData?: Record<string, unknown>;
  userContext?: {
    companyCode?: string;
    userId?: string;
    deptCode?: string;
    userName?: string;
  };
  refreshKey?: number | string;
  /** preview 모드 row 수 (디자인 모드 / dataSource 미설정 시) — 기본 4 */
  previewCount?: number;
  /** 빈 그룹 (null/"") 필터링 — `ChartConfig.includeEmptyGroup` 와 연동 */
  includeEmptyGroup?: boolean;
}

export interface ChartDataState {
  rows: AggregateGroupRow[];
  loading: boolean;
  error?: string;
  /** dataSource 가 아직 채워지지 않아 preview 만 보여주고 있는지 */
  isPreview: boolean;
}

const DEFAULT_PREVIEW: AggregateGroupRow[] = [
  { group: "A", value: 28 },
  { group: "B", value: 19 },
  { group: "C", value: 12 },
  { group: "D", value: 6 },
];

function resolveFilters(
  filters: OptionFilter[] | undefined,
  formData: Record<string, unknown> | undefined,
  userContext: UseChartDataOptions["userContext"],
): { resolved: Array<{ column: string; operator: string; value?: unknown }>; ok: boolean } {
  if (!filters || filters.length === 0) return { resolved: [], ok: true };
  const out: Array<{ column: string; operator: string; value?: unknown }> = [];
  for (const f of filters) {
    if (!f || !f.column) continue;
    const op = f.operator ?? "=";
    if (op === "isNull" || op === "isNotNull") {
      out.push({ column: f.column, operator: op });
      continue;
    }
    let value: unknown = f.value;
    const valueType = f.value_type ?? "static";
    if (valueType === "field") {
      const ref = f.field_ref;
      if (!ref) return { resolved: [], ok: false };
      value = formData?.[ref];
      if (value === undefined) return { resolved: [], ok: false };
    } else if (valueType === "user") {
      const uf = f.user_field;
      if (!uf) return { resolved: [], ok: false };
      value = userContext?.[uf];
      if (value === undefined || value === "") return { resolved: [], ok: false };
    }
    if (value === undefined || value === null) continue;
    out.push({ column: f.column, operator: op, value });
  }
  return { resolved: out, ok: true };
}

function buildRequestKey(
  ds: ChartDataSource,
  filters: Array<{ column: string; operator: string; value?: unknown }>,
  includeEmptyGroup?: boolean,
): string {
  return JSON.stringify({
    t: ds.tableName,
    g: ds.groupBy,
    a: ds.aggregation ?? "count",
    vc: ds.valueColumn ?? "",
    l: ds.limit ?? 12,
    o: ds.orderDir ?? "desc",
    f: filters,
    e: !!includeEmptyGroup,
  });
}

function isDataSourceReady(ds: ChartDataSource | undefined): boolean {
  if (!ds || !ds.tableName || !ds.groupBy) return false;
  const agg = ds.aggregation ?? "count";
  if (agg === "count") return true;
  return !!ds.valueColumn;
}

export function useChartData(
  dataSource: ChartDataSource | undefined,
  opts: UseChartDataOptions = {},
): ChartDataState {
  const { isDesignMode, formData, userContext, refreshKey, previewCount, includeEmptyGroup } = opts;

  const previewRows = useMemo<AggregateGroupRow[]>(() => {
    const n = previewCount ?? DEFAULT_PREVIEW.length;
    return DEFAULT_PREVIEW.slice(0, Math.max(2, Math.min(8, n)));
  }, [previewCount]);

  const [state, setState] = useState<ChartDataState>({
    rows: previewRows,
    loading: false,
    isPreview: true,
  });

  const plan = useMemo(() => {
    if (!isDataSourceReady(dataSource)) return { skip: true as const };
    const { resolved, ok } = resolveFilters(dataSource!.filters, formData, userContext);
    if (!ok) return { skip: true as const, pending: true as const };
    const reqKey = buildRequestKey(dataSource!, resolved, includeEmptyGroup);
    return {
      skip: false as const,
      reqKey,
      req: {
        tableName: dataSource!.tableName!,
        aggregation: dataSource!.aggregation ?? "count",
        groupBy: dataSource!.groupBy!,
        valueColumn: dataSource!.valueColumn,
        filters: resolved,
        limit: dataSource!.limit ?? 12,
        orderDir: dataSource!.orderDir ?? "desc",
      },
    };
  }, [dataSource, formData, userContext, includeEmptyGroup]);

  const cacheRef = useRef<Map<string, AggregateGroupRow[]>>(new Map());
  const versionRef = useRef(0);

  useEffect(() => {
    if (isDesignMode) {
      cacheRef.current.clear();
      setState({ rows: previewRows, loading: false, isPreview: true });
      return;
    }

    if (plan.skip) {
      setState({ rows: previewRows, loading: false, isPreview: true });
      return;
    }

    versionRef.current += 1;
    const myVersion = versionRef.current;
    let cancelled = false;

    if (refreshKey !== undefined) {
      cacheRef.current.clear();
    }

    const cached = cacheRef.current.get(plan.reqKey!);
    if (cached !== undefined && refreshKey === undefined) {
      setState({ rows: cached, loading: false, isPreview: false });
      return;
    }

    setState((prev) => ({ ...prev, loading: true, error: undefined }));

    (async () => {
      try {
        const { rows } = await aggregateTableGroup(plan.req!.tableName, {
          aggregation: plan.req!.aggregation as any,
          groupBy: plan.req!.groupBy,
          valueColumn: plan.req!.valueColumn,
          filters: plan.req!.filters as any,
          limit: plan.req!.limit,
          orderDir: plan.req!.orderDir,
        });
        if (cancelled || versionRef.current !== myVersion) return;
        const filtered = includeEmptyGroup
          ? rows
          : rows.filter((r) => r.group !== null && r.group !== "");
        cacheRef.current.set(plan.reqKey!, filtered);
        setState({ rows: filtered, loading: false, isPreview: false });
      } catch (err: any) {
        if (cancelled || versionRef.current !== myVersion) return;
        const msg = err?.response?.data?.message || err?.message || "차트 데이터 로드 실패";
        setState({ rows: [], loading: false, isPreview: false, error: String(msg) });
      }
    })();

    return () => {
      cancelled = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [plan, isDesignMode, refreshKey, previewRows, includeEmptyGroup]);

  return state;
}
