import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { commonCodeApi } from "@/lib/api/commonCode";
import { tableTypeApi } from "@/lib/api/screen";
import { useMemo } from "react";

// Query Keys
export const queryKeys = {
  codes: {
    all: ["codes"] as const,
    list: (categoryCode: string) => ["codes", "list", categoryCode] as const,
    options: (categoryCode: string) => ["codes", "options", categoryCode] as const,
    detail: (categoryCode: string, codeValue: string) => ["codes", "detail", categoryCode, codeValue] as const,
    infiniteList: (categoryCode: string, filters?: any) => ["codes", "infiniteList", categoryCode, filters] as const,
  },
  tables: {
    all: ["tables"] as const,
    columns: (tableName: string) => ["tables", "columns", tableName] as const,
    codeCategory: (tableName: string, columnName: string) => ["tables", "codeCategory", tableName, columnName] as const,
  },
  categories: {
    all: ["categories"] as const,
    list: (filters?: any) => ["categories", "list", filters] as const,
  },
};

// 테이블 컬럼의 코드 카테고리 조회
export function useTableCodeCategory(tableName?: string, columnName?: string) {
  return useQuery({
    queryKey: queryKeys.tables.codeCategory(tableName || "", columnName || ""),
    queryFn: async () => {
      if (!tableName || !columnName) return null;

      const columns = await tableTypeApi.getColumns(tableName);
      const targetColumn = columns.find((col) => col.columnName === columnName);

      const codeCategory =
        targetColumn?.codeCategory && targetColumn.codeCategory !== "none" ? targetColumn.codeCategory : null;

      return codeCategory;
    },
    enabled: !!(tableName && columnName),
    staleTime: 10 * 60 * 1000, // 10분 캐시
    gcTime: 30 * 60 * 1000, // 30분 가비지 컬렉션
  });
}

// 🆕 테이블 컬럼의 계층구조 설정 조회 (대분류/중분류/소분류)
interface ColumnHierarchyInfo {
  hierarchyRole?: "large" | "medium" | "small";
  hierarchyParentField?: string;
  codeCategory?: string;
}

export function useTableColumnHierarchy(tableName?: string, columnName?: string) {
  return useQuery<ColumnHierarchyInfo | null>({
    queryKey: ["tables", "hierarchy", tableName || "", columnName || ""],
    queryFn: async () => {
      if (!tableName || !columnName) return null;

      const columns = await tableTypeApi.getColumns(tableName);
      const targetColumn = columns.find((col) => col.columnName === columnName);

      if (!targetColumn) return null;

      // detailSettings에서 hierarchyRole 추출
      let hierarchyRole: ColumnHierarchyInfo["hierarchyRole"];
      let hierarchyParentField: string | undefined;

      if (targetColumn.detailSettings) {
        try {
          const settings =
            typeof targetColumn.detailSettings === "string"
              ? JSON.parse(targetColumn.detailSettings)
              : targetColumn.detailSettings;

          hierarchyRole = settings.hierarchyRole;
          hierarchyParentField = settings.hierarchyParentField;
        } catch {
          // JSON 파싱 실패 시 무시
        }
      }

      // hierarchyParentField가 없으면 같은 codeCategory를 가진 상위 역할 컬럼을 자동으로 찾음
      if (hierarchyRole && !hierarchyParentField && targetColumn.codeCategory) {
        const roleOrder = { large: 0, medium: 1, small: 2 };
        const currentOrder = roleOrder[hierarchyRole];

        if (currentOrder > 0) {
          // 같은 codeCategory를 가진 컬럼들 중에서 상위 역할을 찾음
          const parentRole = currentOrder === 1 ? "large" : "medium";

          const parentColumn = columns.find((col) => {
            if (col.codeCategory !== targetColumn.codeCategory) return false;

            try {
              const colSettings =
                typeof col.detailSettings === "string" ? JSON.parse(col.detailSettings) : col.detailSettings;
              return colSettings?.hierarchyRole === parentRole;
            } catch {
              return false;
            }
          });

          if (parentColumn) {
            hierarchyParentField = parentColumn.columnName;
          }
        }
      }

      return {
        hierarchyRole,
        hierarchyParentField,
        codeCategory: targetColumn.codeCategory,
      };
    },
    enabled: !!(tableName && columnName),
    staleTime: 10 * 60 * 1000,
    gcTime: 30 * 60 * 1000,
  });
}

// 코드 옵션 조회 (select용)
export function useCodeOptions(codeCategory?: string, enabled: boolean = true, menuObjid?: number) {
  const query = useQuery({
    queryKey: menuObjid
      ? [...queryKeys.codes.options(codeCategory || ""), "menu", menuObjid]
      : queryKeys.codes.options(codeCategory || ""),
    queryFn: async () => {
      if (!codeCategory || codeCategory === "none") return [];

      const response = await commonCodeApi.codes.getList(codeCategory, {
        isActive: true,
        menuObjid,
      });

      if (response.success && response.data) {
        const options = response.data.map((code: any) => {
          const actualValue = code.code || code.CODE || code.value || code.code_value || code.codeValue;
          const actualLabel =
            code.codeName ||
            code.code_name ||
            code.name ||
            code.CODE_NAME ||
            code.NAME ||
            code.label ||
            code.LABEL ||
            code.text ||
            code.title ||
            code.description ||
            actualValue;

          // 계층구조 정보 포함
          const depth = code.depth ?? 1;
          const parentCodeValue = code.parentCodeValue || code.parent_code_value || null;

          return {
            value: actualValue,
            label: actualLabel,
            depth,
            parentCodeValue,
          };
        });

        return options;
      }

      return [];
    },
    enabled: enabled && !!(codeCategory && codeCategory !== "none"),
    staleTime: 10 * 60 * 1000, // 10분 캐시
    gcTime: 30 * 60 * 1000, // 30분 가비지 컬렉션
  });

  return {
    options: query.data || [],
    isLoading: query.isLoading,
    isFetching: query.isFetching,
    error: query.error,
    refetch: query.refetch,
  };
}

// 코드 생성
export function useCreateCode() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: ({ categoryCode, data }: { categoryCode: string; data: any }) =>
      commonCodeApi.codes.create(categoryCode, data),
    onSuccess: (_, variables) => {
      // 해당 카테고리의 모든 코드 관련 쿼리 무효화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.all,
      });
      // 무한 스크롤 쿼리도 명시적으로 무효화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.infiniteList(variables.categoryCode),
      });
    },
  });
}

// 코드 수정
export function useUpdateCode() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: ({ categoryCode, codeValue, data }: { categoryCode: string; codeValue: string; data: any }) =>
      commonCodeApi.codes.update(categoryCode, codeValue, data),
    onSuccess: (_, variables) => {
      // 해당 코드 상세 쿼리 무효화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.detail(variables.categoryCode, variables.codeValue),
      });
      // 해당 카테고리의 모든 코드 관련 쿼리 무효화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.all,
      });
      // 무한 스크롤 쿼리도 명시적으로 무효화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.infiniteList(variables.categoryCode),
      });
    },
  });
}

// 코드 삭제
export function useDeleteCode() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: ({ categoryCode, codeValue }: { categoryCode: string; codeValue: string }) =>
      commonCodeApi.codes.delete(categoryCode, codeValue),
    onSuccess: (_, variables) => {
      // 해당 코드 관련 쿼리 무효화 및 캐시 제거
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.all,
      });
      // 무한 스크롤 쿼리도 명시적으로 무효화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.infiniteList(variables.categoryCode),
      });
      queryClient.removeQueries({
        queryKey: queryKeys.codes.detail(variables.categoryCode, variables.codeValue),
      });
    },
  });
}

// 코드 순서 변경
export function useReorderCodes() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: ({
      categoryCode,
      codes,
    }: {
      categoryCode: string;
      codes: Array<{ codeValue: string; sortOrder: number }>;
    }) => commonCodeApi.codes.reorder(categoryCode, codes),
    onMutate: async ({ categoryCode, codes }) => {
      // 진행 중인 쿼리들을 취소해서 optimistic update가 덮어쓰이지 않도록 함
      await queryClient.cancelQueries({ queryKey: queryKeys.codes.list(categoryCode) });

      // 이전 데이터를 백업
      const previousCodes = queryClient.getQueryData(queryKeys.codes.list(categoryCode));

      // Optimistic update: 새로운 순서로 즉시 업데이트
      if (previousCodes && Array.isArray((previousCodes as any).data)) {
        const previousCodesArray = (previousCodes as any).data;

        // 기존 데이터를 복사하고 sort_order만 업데이트
        const updatedCodes = [...previousCodesArray].map((code: any) => {
          const newCodeData = codes.find((c) => c.codeValue === code.code_value);
          return newCodeData ? { ...code, sort_order: newCodeData.sortOrder } : code;
        });

        // 순서대로 정렬
        updatedCodes.sort((a, b) => (a.sort_order || 0) - (b.sort_order || 0));

        // API 응답 형태로 캐시에 저장 (기존 구조 유지)
        queryClient.setQueryData(queryKeys.codes.list(categoryCode), {
          ...(previousCodes as any),
          data: updatedCodes,
        });
      }

      return { previousCodes };
    },
    onError: (err, variables, context) => {
      // 에러 시 이전 데이터로 롤백
      if (context?.previousCodes) {
        queryClient.setQueryData(queryKeys.codes.list(variables.categoryCode), context.previousCodes);
      }
    },
    onSettled: (_, __, variables) => {
      // 성공/실패와 관계없이 최종적으로 서버 데이터로 동기화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.all,
      });
      // 무한 스크롤 쿼리도 명시적으로 무효화
      queryClient.invalidateQueries({
        queryKey: queryKeys.codes.infiniteList(variables.categoryCode),
      });
    },
  });
}
