"use client";

import { useState, useCallback, useEffect, useMemo, useRef } from "react";
import { apiClient } from "@/lib/api/client";
import { v2EventBus, V2_EVENTS } from "@/lib/v2-core";
import { TimelineSchedulerConfig, ScheduleItem, Resource, ZoomLevel, UseTimelineDataResult } from "../types";
import { zoomLevelDays, defaultTimelineSchedulerConfig } from "../config";

// schedule_mng 테이블 고정 (공통 스케줄 테이블)
const SCHEDULE_TABLE = "schedule_mng";

/**
 * 날짜를 ISO 문자열로 변환 (시간 제외)
 */
const toDateString = (date: Date): string => {
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
};

/**
 * 날짜 더하기
 */
const addDays = (date: Date, days: number): Date => {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
};

/**
 * 타임라인 데이터를 관리하는 훅
 */
export function useTimelineData(
  config: TimelineSchedulerConfig,
  externalSchedules?: ScheduleItem[],
  externalResources?: Resource[],
): UseTimelineDataResult {
  // 상태
  const [schedules, setSchedules] = useState<ScheduleItem[]>([]);
  const [resources, setResources] = useState<Resource[]>([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [zoomLevel, setZoomLevel] = useState<ZoomLevel>(config.defaultZoomLevel || "day");
  const [viewStartDate, setViewStartDate] = useState<Date>(() => {
    if (config.initialDate) {
      return new Date(config.initialDate);
    }
    // 오늘 기준 1주일 전부터 시작
    const today = new Date();
    today.setDate(today.getDate() - 7);
    today.setHours(0, 0, 0, 0);
    return today;
  });

  // 선택된 품목 코드 (좌측 테이블에서 선택된 데이터 기준)
  const [selectedSourceKeys, setSelectedSourceKeys] = useState<string[]>([]);
  const selectedSourceKeysRef = useRef<string[]>([]);

  // 표시 종료일 계산
  const viewEndDate = useMemo(() => {
    const days = zoomLevelDays[zoomLevel];
    return addDays(viewStartDate, days);
  }, [viewStartDate, zoomLevel]);

  // 테이블명: 기본적으로 schedule_mng 사용, 커스텀 테이블 설정 시 해당 테이블 사용
  const tableName = config.useCustomTable && config.customTableName ? config.customTableName : SCHEDULE_TABLE;

  const resourceTableName = config.resourceTable;

  // 필드 매핑을 JSON 문자열로 안정화 (객체 참조 변경 방지)
  const fieldMappingKey = useMemo(() => {
    return JSON.stringify(config.fieldMapping || {});
  }, [config.fieldMapping]);

  const resourceFieldMappingKey = useMemo(() => {
    return JSON.stringify(config.resourceFieldMapping || {});
  }, [config.resourceFieldMapping]);

  // 🆕 필드 매핑 정규화 (이전 형식 → 새 형식 변환) - useMemo로 메모이제이션
  const fieldMapping = useMemo(() => {
    const mapping = config.fieldMapping;
    if (!mapping) return defaultTimelineSchedulerConfig.fieldMapping!;

    return {
      id: mapping.id || mapping.idField || "id",
      resourceId: mapping.resourceId || mapping.resourceIdField || "resource_id",
      title: mapping.title || mapping.titleField || "title",
      startDate: mapping.startDate || mapping.startDateField || "start_date",
      endDate: mapping.endDate || mapping.endDateField || "end_date",
      status: mapping.status || mapping.statusField || undefined,
      progress: mapping.progress || mapping.progressField || undefined,
      color: mapping.color || mapping.colorField || undefined,
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fieldMappingKey]);

  // 리소스 필드 매핑 - useMemo로 메모이제이션
  const resourceFieldMapping = useMemo(() => {
    return config.resourceFieldMapping || defaultTimelineSchedulerConfig.resourceFieldMapping!;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [resourceFieldMappingKey]);

  // 스케줄 데이터 로드
  const fetchSchedules = useCallback(async () => {
    if (externalSchedules) {
      setSchedules(externalSchedules);
      return;
    }

    if (!tableName) {
      setSchedules([]);
      return;
    }

    setIsLoading(true);
    setError(null);

    try {
      // schedule_mng 테이블 사용 시 필터 조건 구성
      const isScheduleMng = tableName === SCHEDULE_TABLE;
      const currentSourceKeys = selectedSourceKeysRef.current;

      console.log("[useTimelineData] 스케줄 조회:", {
        tableName,
        scheduleType: config.scheduleType,
        sourceKeys: currentSourceKeys,
      });

      const searchParams: Record<string, any> = {};
      if (!isScheduleMng && config.staticFilters) {
        Object.assign(searchParams, config.staticFilters);
      }

      const response = await apiClient.post(`/table-management/tables/${tableName}/data`, {
        page: 1,
        size: 10000,
        autoFilter: true,
        ...(Object.keys(searchParams).length > 0 ? { search: searchParams } : {}),
      });

      const responseData = response.data?.data?.data || response.data?.data || [];
      let rawData = Array.isArray(responseData) ? responseData : [];

      // 클라이언트 측 필터링 적용 (schedule_mng 테이블인 경우)
      if (isScheduleMng) {
        // 스케줄 타입 필터
        if (config.scheduleType) {
          rawData = rawData.filter((row: any) => row.schedule_type === config.scheduleType);
        }

        // 선택된 품목 필터 (source_group_key 기준)
        if (currentSourceKeys.length > 0) {
          rawData = rawData.filter((row: any) => currentSourceKeys.includes(row.source_group_key));
        }

        console.log("[useTimelineData] 필터링 후 스케줄:", rawData.length, "건");
      }

      // schedule_mng 테이블용 필드 매핑 (고정)
      const scheduleMngFieldMapping = {
        id: "schedule_id",
        resourceId: "resource_id",
        title: "schedule_name",
        startDate: "start_date",
        endDate: "end_date",
        status: "status",
        progress: undefined, // actual_qty / plan_qty로 계산 가능
      };

      // 사용할 필드 매핑 결정
      const effectiveMapping = isScheduleMng ? scheduleMngFieldMapping : fieldMapping;

      // 데이터를 ScheduleItem 형태로 변환
      const mappedSchedules: ScheduleItem[] = rawData.map((row: any) => {
        // 진행률 계산 (schedule_mng일 경우)
        let progress: number | undefined;
        if (isScheduleMng && row.plan_qty && row.plan_qty > 0) {
          progress = Math.round(((row.actual_qty || 0) / row.plan_qty) * 100);
        } else if (effectiveMapping.progress) {
          progress = Number(row[effectiveMapping.progress]) || 0;
        }

        return {
          id: String(row[effectiveMapping.id] || ""),
          resourceId: String(row[effectiveMapping.resourceId] || ""),
          title: String(row[effectiveMapping.title] || ""),
          startDate: row[effectiveMapping.startDate] || "",
          endDate: row[effectiveMapping.endDate] || "",
          status: effectiveMapping.status ? row[effectiveMapping.status] || "planned" : "planned",
          progress,
          color: fieldMapping.color ? row[fieldMapping.color] : undefined,
          data: row,
        };
      });

      console.log("[useTimelineData] 스케줄 로드 완료:", mappedSchedules.length, "건");
      setSchedules(mappedSchedules);
    } catch (err: any) {
      console.error("[useTimelineData] 스케줄 로드 오류:", err);
      setError(err.message || "스케줄 데이터 로드 중 오류 발생");
      setSchedules([]);
    } finally {
      setIsLoading(false);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [tableName, externalSchedules, fieldMappingKey, config.scheduleType, JSON.stringify(config.staticFilters)]);

  // 리소스 데이터 로드
  const fetchResources = useCallback(async () => {
    if (externalResources) {
      setResources(externalResources);
      return;
    }

    if (!resourceTableName) {
      setResources([]);
      return;
    }

    try {
      const response = await apiClient.post(`/table-management/tables/${resourceTableName}/data`, {
        page: 1,
        size: 1000,
        autoFilter: true,
      });

      const responseData = response.data?.data?.data || response.data?.data || [];
      const rawData = Array.isArray(responseData) ? responseData : [];

      // 데이터를 Resource 형태로 변환
      const mappedResources: Resource[] = rawData.map((row: any) => ({
        id: String(row[resourceFieldMapping.id] || ""),
        name: String(row[resourceFieldMapping.name] || ""),
        group: resourceFieldMapping.group ? row[resourceFieldMapping.group] : undefined,
      }));

      setResources(mappedResources);
    } catch (err: any) {
      console.error("리소스 로드 오류:", err);
      setResources([]);
    }
    // resourceFieldMappingKey를 의존성으로 사용하여 객체 참조 변경 방지
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [resourceTableName, externalResources, resourceFieldMappingKey]);

  // 초기 로드
  useEffect(() => {
    fetchSchedules();
  }, [fetchSchedules]);

  useEffect(() => {
    fetchResources();
  }, [fetchResources]);

  // 이벤트 버스 리스너 - 테이블 선택 변경 (품목 선택 시 해당 스케줄만 표시)
  useEffect(() => {
    const unsubscribeSelection = v2EventBus.subscribe(V2_EVENTS.TABLE_SELECTION_CHANGE, (payload) => {
      console.log("[useTimelineData] TABLE_SELECTION_CHANGE 수신:", {
        tableName: payload.tableName,
        selectedCount: payload.selectedCount,
      });

      // 설정된 그룹 필드명 사용 (없으면 기본값들 fallback)
      const groupByField = config.sourceConfig?.groupByField;

      // 선택된 데이터에서 source_group_key 추출
      const sourceKeys: string[] = [];
      for (const row of payload.selectedRows || []) {
        // 설정된 필드명 우선, 없으면 일반적인 필드명 fallback
        let key: string | undefined;
        if (groupByField && row[groupByField]) {
          key = row[groupByField];
        } else {
          // fallback: 일반적으로 사용되는 필드명들
          key = row.part_code || row.source_group_key || row.item_code;
        }

        if (key && !sourceKeys.includes(key)) {
          sourceKeys.push(key);
        }
      }

      console.log("[useTimelineData] 선택된 그룹 키:", {
        groupByField,
        keys: sourceKeys,
      });

      // 상태 업데이트 및 ref 동기화
      selectedSourceKeysRef.current = sourceKeys;
      setSelectedSourceKeys(sourceKeys);
    });

    return () => {
      unsubscribeSelection();
    };
  }, [config.sourceConfig?.groupByField]);

  // 선택된 품목이 변경되면 스케줄 다시 로드
  useEffect(() => {
    if (tableName === SCHEDULE_TABLE) {
      console.log("[useTimelineData] 선택 품목 변경으로 스케줄 새로고침:", selectedSourceKeys);
      fetchSchedules();
    }
  }, [selectedSourceKeys, tableName, fetchSchedules]);

  // 이벤트 버스 리스너 - 스케줄 생성 완료 및 테이블 새로고침
  useEffect(() => {
    // TABLE_REFRESH 이벤트 수신 - 스케줄 새로고침
    const unsubscribeRefresh = v2EventBus.subscribe(V2_EVENTS.TABLE_REFRESH, (payload) => {
      // schedule_mng 또는 해당 테이블에 대한 새로고침
      if (payload.tableName === tableName || payload.tableName === SCHEDULE_TABLE) {
        console.log("[useTimelineData] TABLE_REFRESH 수신, 스케줄 새로고침:", payload);
        fetchSchedules();
      }
    });

    // SCHEDULE_GENERATE_COMPLETE 이벤트 수신 - 스케줄 자동 생성 완료 시 새로고침
    const unsubscribeComplete = v2EventBus.subscribe(V2_EVENTS.SCHEDULE_GENERATE_COMPLETE, (payload) => {
      if (payload.success) {
        console.log("[useTimelineData] SCHEDULE_GENERATE_COMPLETE 수신, 스케줄 새로고침:", payload);
        fetchSchedules();
      }
    });

    return () => {
      unsubscribeRefresh();
      unsubscribeComplete();
    };
  }, [tableName, fetchSchedules]);

  // 네비게이션 함수들
  const goToPrevious = useCallback(() => {
    const days = zoomLevelDays[zoomLevel];
    setViewStartDate((prev) => addDays(prev, -days));
  }, [zoomLevel]);

  const goToNext = useCallback(() => {
    const days = zoomLevelDays[zoomLevel];
    setViewStartDate((prev) => addDays(prev, days));
  }, [zoomLevel]);

  const goToToday = useCallback(() => {
    const today = new Date();
    today.setDate(today.getDate() - 7);
    today.setHours(0, 0, 0, 0);
    setViewStartDate(today);
  }, []);

  const goToDate = useCallback((date: Date) => {
    const newDate = new Date(date);
    newDate.setDate(newDate.getDate() - 7);
    newDate.setHours(0, 0, 0, 0);
    setViewStartDate(newDate);
  }, []);

  // 스케줄 업데이트
  const updateSchedule = useCallback(
    async (id: string, updates: Partial<ScheduleItem>) => {
      if (!tableName || !config.editable) return;

      try {
        // 필드 매핑 역변환
        const updateData: Record<string, any> = {};
        if (updates.startDate) updateData[fieldMapping.startDate] = updates.startDate;
        if (updates.endDate) updateData[fieldMapping.endDate] = updates.endDate;
        if (updates.resourceId) updateData[fieldMapping.resourceId] = updates.resourceId;
        if (updates.title) updateData[fieldMapping.title] = updates.title;
        if (updates.status && fieldMapping.status) updateData[fieldMapping.status] = updates.status;
        if (updates.progress !== undefined && fieldMapping.progress)
          updateData[fieldMapping.progress] = updates.progress;

        await apiClient.put(`/table-management/tables/${tableName}/data/${id}`, updateData);

        // 로컬 상태 업데이트
        setSchedules((prev) => prev.map((s) => (s.id === id ? { ...s, ...updates } : s)));
      } catch (err: any) {
        console.error("스케줄 업데이트 오류:", err);
        throw err;
      }
    },
    [tableName, fieldMapping, config.editable],
  );

  // 스케줄 추가
  const addSchedule = useCallback(
    async (schedule: Omit<ScheduleItem, "id">) => {
      if (!tableName || !config.editable) return;

      try {
        // 필드 매핑 역변환
        const insertData: Record<string, any> = {
          [fieldMapping.resourceId]: schedule.resourceId,
          [fieldMapping.title]: schedule.title,
          [fieldMapping.startDate]: schedule.startDate,
          [fieldMapping.endDate]: schedule.endDate,
        };

        if (fieldMapping.status) insertData[fieldMapping.status] = schedule.status;
        if (fieldMapping.progress && schedule.progress !== undefined)
          insertData[fieldMapping.progress] = schedule.progress;

        const response = await apiClient.post(`/table-management/tables/${tableName}/data`, insertData);

        const newId = response.data?.data?.id || Date.now().toString();

        // 로컬 상태 업데이트
        setSchedules((prev) => [...prev, { ...schedule, id: newId }]);
      } catch (err: any) {
        console.error("스케줄 추가 오류:", err);
        throw err;
      }
    },
    [tableName, fieldMapping, config.editable],
  );

  // 스케줄 삭제
  const deleteSchedule = useCallback(
    async (id: string) => {
      if (!tableName || !config.editable) return;

      try {
        await apiClient.delete(`/table-management/tables/${tableName}/data/${id}`);

        // 로컬 상태 업데이트
        setSchedules((prev) => prev.filter((s) => s.id !== id));
      } catch (err: any) {
        console.error("스케줄 삭제 오류:", err);
        throw err;
      }
    },
    [tableName, config.editable],
  );

  // 새로고침
  const refresh = useCallback(() => {
    fetchSchedules();
    fetchResources();
  }, [fetchSchedules, fetchResources]);

  return {
    schedules,
    resources,
    isLoading,
    error,
    zoomLevel,
    setZoomLevel,
    viewStartDate,
    viewEndDate,
    goToPrevious,
    goToNext,
    goToToday,
    goToDate,
    updateSchedule,
    addSchedule,
    deleteSchedule,
    refresh,
  };
}
