"use client";

/**
 * @module ReportDesignerContext
 * @description 리포트 디자이너의 전역 상태를 제공하는 Context.
 *
 * 이 파일은 얇은 조합 레이어(thin orchestrator)로, 실제 로직은 각 훅에 위임한다.
 *
 * 책임 분배:
 * - useSelectionState    → 컴포넌트 선택 상태 (단일/다중)
 * - usePageManager       → 페이지 CRUD 및 설정 변경
 * - useQueryManager      → 쿼리 정의 및 실행 결과 캐시
 * - useUIState           → 그리드/줌/패널/정렬 가이드 등 UI 전용 상태
 * - useHistoryManager    → Undo/Redo 이력 관리
 * - useClipboardActions  → 복사/붙여넣기/복제/스타일 전달
 * - useAlignmentActions  → 정렬·균등 배치·크기 동일화
 * - useLayerActions      → 레이어 순서·잠금·그룹화
 * - useLayoutIO          → 서버 저장/로드 및 템플릿 적용
 */

import {
  createContext,
  useContext,
  useState,
  useCallback,
  ReactNode,
  useEffect,
  useRef,
} from "react";
import {
  ComponentConfig,
  ReportDetail,
  ReportLayout,
  ReportPage,
  ReportLayoutConfig,
  WatermarkConfig,
} from "@/types/report";
import { useToast } from "@/hooks/use-toast";

// 각 역할별 훅
import { useSelectionState } from "./report-designer/useSelectionState";
import { usePageManager } from "./report-designer/usePageManager";
import { useQueryManager } from "./report-designer/useQueryManager";
import { useUIState } from "./report-designer/useUIState";
import { useHistoryManager } from "./report-designer/useHistoryManager";
import { useClipboardActions } from "./report-designer/useClipboardActions";
import { useAlignmentActions } from "./report-designer/useAlignmentActions";
import { useLayerActions } from "./report-designer/useLayerActions";
import { useLayoutIO } from "./report-designer/useLayoutIO";

// 공유 타입
export type { ReportQuery, QueryResult } from "./report-designer/types";

// ─────────────────────────────────────────────
// Context 타입 정의
// ─────────────────────────────────────────────

interface ReportDesignerContextType {
  reportId: string;
  reportDetail: ReportDetail | null;
  layout: ReportLayout | null;

  // 페이지 관리
  layoutConfig: ReportLayoutConfig;
  currentPageId: string | null;
  currentPage: ReportPage | undefined;
  addPage: (name?: string) => void;
  deletePage: (pageId: string) => void;
  duplicatePage: (pageId: string) => void;
  reorderPages: (sourceIndex: number, targetIndex: number) => void;
  selectPage: (pageId: string) => void;
  updatePageSettings: (pageId: string, settings: Partial<ReportPage>) => void;
  updateWatermark: (watermark: WatermarkConfig | undefined) => void;

  // 컴포넌트 (현재 페이지)
  components: ComponentConfig[];
  selectedComponentId: string | null;
  selectedComponentIds: string[];
  isLoading: boolean;
  isSaving: boolean;
  addComponent: (component: ComponentConfig) => void;
  updateComponent: (id: string, updates: Partial<ComponentConfig>) => void;
  removeComponent: (id: string) => void;
  selectComponent: (id: string | null, isMultiSelect?: boolean) => void;
  selectMultipleComponents: (ids: string[]) => void;

  // 레이아웃 관리
  updateLayout: (updates: Partial<ReportLayout>) => void;
  saveLayout: () => Promise<void>;
  loadLayout: () => Promise<void>;
  applyTemplate: (templateId: string) => Promise<void>;

  // 캔버스 설정 (현재 페이지 기반)
  canvasWidth: number;
  canvasHeight: number;
  pageOrientation: string;
  margins: { top: number; bottom: number; left: number; right: number };

  // UI 도구
  gridSize: number;
  setGridSize: (size: number) => void;
  showGrid: boolean;
  setShowGrid: (show: boolean) => void;
  snapToGrid: boolean;
  setSnapToGrid: (snap: boolean) => void;
  snapValueToGrid: (value: number) => number;
  alignmentGuides: { vertical: number[]; horizontal: number[] };
  calculateAlignmentGuides: (draggingId: string, x: number, y: number, width: number, height: number) => void;
  clearAlignmentGuides: () => void;

  // 복사/붙여넣기
  copyComponents: () => void;
  pasteComponents: () => void;
  duplicateComponents: () => void;
  copyStyles: () => void;
  pasteStyles: () => void;
  duplicateAtPosition: (componentIds: string[], offsetX?: number, offsetY?: number) => string[];
  fitSelectedToContent: () => void;

  // Undo/Redo
  undo: () => void;
  redo: () => void;
  canUndo: boolean;
  canRedo: boolean;

  // 정렬 기능
  alignLeft: () => void;
  alignRight: () => void;
  alignTop: () => void;
  alignBottom: () => void;
  alignCenterHorizontal: () => void;
  alignCenterVertical: () => void;
  distributeHorizontal: () => void;
  distributeVertical: () => void;
  makeSameWidth: () => void;
  makeSameHeight: () => void;
  makeSameSize: () => void;

  // 레이어 관리
  bringToFront: () => void;
  sendToBack: () => void;
  bringForward: () => void;
  sendBackward: () => void;
  toggleLock: () => void;
  lockComponents: () => void;
  unlockComponents: () => void;

  // 눈금자 표시
  showRuler: boolean;
  setShowRuler: (show: boolean) => void;

  // 캔버스 줌
  zoom: number;
  setZoom: (zoom: number) => void;
  fitTrigger: number;
  fitToScreen: () => void;

  // 그룹화
  groupComponents: () => void;
  ungroupComponents: () => void;

  // 메뉴 연결
  menuObjids: number[];
  setMenuObjids: (menuObjids: number[]) => void;
  saveLayoutWithMenus: (menuObjids: number[]) => Promise<void>;

  // 쿼리 관리
  queries: import("./report-designer/types").ReportQuery[];
  setQueries: (queries: import("./report-designer/types").ReportQuery[]) => void;
  queryResults: import("./report-designer/types").QueryResult[];
  setQueryResult: (queryId: string, fields: string[], rows: Record<string, unknown>[]) => void;
  getQueryResult: (queryId: string) => import("./report-designer/types").QueryResult | null;

  // 인캔버스 설정 모달
  componentModalTargetId: string | null;
  openComponentModal: (componentId: string) => void;
  closeComponentModal: () => void;

  // 패널 접기/펼치기
  isPageListCollapsed: boolean;
  setIsPageListCollapsed: (v: boolean) => void;
  isLeftPanelCollapsed: boolean;
  setIsLeftPanelCollapsed: (v: boolean) => void;
  isRightPanelCollapsed: boolean;
  setIsRightPanelCollapsed: (v: boolean) => void;
}

const ReportDesignerContext = createContext<ReportDesignerContextType | undefined>(undefined);

// ─────────────────────────────────────────────
// Provider
// ─────────────────────────────────────────────

export function ReportDesignerProvider({
  reportId,
  children,
}: {
  reportId: string;
  children: ReactNode;
}) {
  const { toast } = useToast();

  // ── 공유 레이아웃 상태 (여러 훅이 공유) ──
  const [layoutConfig, setLayoutConfig] = useState<ReportLayoutConfig>({ pages: [] });
  const [currentPageId, setCurrentPageId] = useState<string | null>(null);
  const [reportDetail, setReportDetail] = useState<ReportDetail | null>(null);
  const [layout, setLayout] = useState<ReportLayout | null>(null);
  const [menuObjids, setMenuObjids] = useState<number[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);

  // currentPageId를 ref로 유지하여 클로저 내에서도 최신 값을 읽을 수 있게 한다
  const currentPageIdRef = useRef<string | null>(currentPageId);
  useEffect(() => { currentPageIdRef.current = currentPageId; }, [currentPageId]);

  // ── 파생 값 ──
  const currentPage = layoutConfig.pages.find((p) => p.page_id === currentPageId);
  const components: ComponentConfig[] = Array.isArray(currentPage?.components) ? currentPage.components : [];

  // 현재 페이지의 컴포넌트를 업데이트하는 공유 헬퍼 (ref 기반으로 클로저 문제 회피)
  const setComponents = useCallback(
    (updater: ComponentConfig[] | ((prev: ComponentConfig[]) => ComponentConfig[])) => {
      setLayoutConfig((prev) => {
        const pageId = currentPageIdRef.current;
        if (!pageId) return prev;
        const pageIndex = prev.pages.findIndex((p) => p.page_id === pageId);
        if (pageIndex === -1) return prev;
        const page = prev.pages[pageIndex];
        const newComponents = typeof updater === "function" ? updater(page.components) : updater;
        const newPages = [...prev.pages];
        newPages[pageIndex] = { ...page, components: newComponents };
        return { ...prev, pages: newPages };
      });
    },
    [], // ref를 사용하므로 의존성 배열 비움
  );

  // 캔버스 치수 (현재 페이지 기반, 단위: mm)
  const canvasWidth = currentPage?.width ?? 210;
  const canvasHeight = currentPage?.height ?? 297;
  const pageOrientation = currentPage?.orientation ?? "portrait";
  const margins = currentPage?.margins ?? { top: 20, bottom: 20, left: 20, right: 20 };

  // ── 각 역할별 훅 조합 ──

  const selection = useSelectionState();

  const pageManager = usePageManager({
    layoutConfig,
    setLayoutConfig,
    currentPageId,
    setCurrentPageId,
    clearSelection: selection.clearSelection,
    toast,
  });

  const queryManager = useQueryManager();

  const uiState = useUIState(components, { canvasWidth, canvasHeight });

  const historyManager = useHistoryManager(components, setComponents, isLoading, toast);

  const clipboard = useClipboardActions({
    components,
    selectedComponentId: selection.selectedComponentId,
    selectedComponentIds: selection.selectedComponentIds,
    setComponents,
    currentPage,
    currentPageId,
    setLayoutConfig,
    snapToGrid: uiState.snapToGrid,
    gridSize: uiState.gridSize,
    toast,
  });

  const alignment = useAlignmentActions({
    components,
    selectedComponentIds: selection.selectedComponentIds,
    setComponents,
    toast,
  });

  const layer = useLayerActions({
    components,
    selectedComponentId: selection.selectedComponentId,
    selectedComponentIds: selection.selectedComponentIds,
    setComponents,
    toast,
  });

  const layoutIO = useLayoutIO({
    reportId,
    layoutConfig,
    queries: queryManager.queries,
    menuObjids,
    setMenuObjids,
    setIsLoading,
    setIsSaving,
    setReportDetail,
    setLayout,
    setLayoutConfig,
    setCurrentPageId,
    setQueries: queryManager.setQueries,
    setComponents,
    currentPageIdRef,
    toast,
  });

  // ── 초기 로드 ──
  useEffect(() => {
    layoutIO.loadLayout();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [reportId]);

  // ── 초기 히스토리 설정 (레이아웃 로드 완료 시) ──
  useEffect(() => {
    if (!isLoading && components.length > 0) {
      historyManager.initHistory(components);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isLoading]);

  // ── 컴포넌트 관리 (현재 페이지 직접 조작) ──

  /** 현재 페이지에 새 컴포넌트를 추가한다. */
  const addComponent = useCallback(
    (component: ComponentConfig) => setComponents((prev) => [...prev, component]),
    [setComponents],
  );

  /** 현재 페이지에서 특정 컴포넌트의 속성을 업데이트한다. */
  const updateComponent = useCallback(
    (id: string, updates: Partial<ComponentConfig>) => {
      if (!currentPageId) return;
      setLayoutConfig((prev) => ({
        pages: prev.pages.map((page) =>
          page.page_id === currentPageId
            ? { ...page, components: page.components.map((c) => (c.id === id ? { ...c, ...updates } : c)) }
            : page,
        ),
      }));
    },
    [currentPageId],
  );

  /** 현재 페이지에서 특정 컴포넌트를 삭제하고 선택 상태를 정리한다. */
  const removeComponent = useCallback(
    (id: string) => {
      if (!currentPageId) return;
      setLayoutConfig((prev) => ({
        pages: prev.pages.map((page) =>
          page.page_id === currentPageId
            ? { ...page, components: page.components.filter((c) => c.id !== id) }
            : page,
        ),
      }));
      if (selection.selectedComponentId === id) selection.setSelectedComponentId(null);
      selection.setSelectedComponentIds((prev) => prev.filter((compId) => compId !== id));
    },
    [currentPageId, selection],
  );

  /**
   * 레이아웃 메타데이터(canvas_width, page_orientation 등)를 업데이트한다.
   * 현재 페이지의 페이지 설정과 동기화된다.
   */
  const updateLayout = useCallback(
    (updates: Partial<ReportLayout>) => {
      setLayout((prev) => (prev ? { ...prev, ...updates } : null));
      if (!currentPageId) return;

      const pageUpdates: Partial<ReportPage> = {};
      if (updates.canvas_width !== undefined) pageUpdates.width = updates.canvas_width;
      if (updates.canvas_height !== undefined) pageUpdates.height = updates.canvas_height;
      if (updates.page_orientation !== undefined)
        pageUpdates.orientation = updates.page_orientation as "portrait" | "landscape";

      if (
        updates.margin_top !== undefined ||
        updates.margin_bottom !== undefined ||
        updates.margin_left !== undefined ||
        updates.margin_right !== undefined
      ) {
        pageUpdates.margins = {
          top: updates.margin_top ?? currentPage?.margins.top ?? 20,
          bottom: updates.margin_bottom ?? currentPage?.margins.bottom ?? 20,
          left: updates.margin_left ?? currentPage?.margins.left ?? 20,
          right: updates.margin_right ?? currentPage?.margins.right ?? 20,
        };
      }

      if (Object.keys(pageUpdates).length > 0) {
        pageManager.updatePageSettings(currentPageId, pageUpdates);
      }
    },
    [currentPageId, currentPage, pageManager, setLayout],
  );

  // ─────────────────────────────────────────────
  // Context 값 조합
  // ─────────────────────────────────────────────

  const value: ReportDesignerContextType = {
    reportId,
    reportDetail,
    layout,

    // 페이지 관리
    layoutConfig,
    currentPageId,
    currentPage,
    ...pageManager,

    // 컴포넌트 상태 및 관리
    components,
    isLoading,
    isSaving,
    addComponent,
    updateComponent,
    removeComponent,
    updateLayout,

    // 선택 상태
    selectedComponentId: selection.selectedComponentId,
    selectedComponentIds: selection.selectedComponentIds,
    selectComponent: selection.selectComponent,
    selectMultipleComponents: selection.selectMultipleComponents,

    // 레이아웃 I/O
    saveLayout: layoutIO.saveLayout,
    loadLayout: layoutIO.loadLayout,
    applyTemplate: layoutIO.applyTemplate,
    saveLayoutWithMenus: layoutIO.saveLayoutWithMenus,

    // 캔버스 설정
    canvasWidth,
    canvasHeight,
    pageOrientation,
    margins,

    // UI 상태
    ...uiState,

    // 복사/붙여넣기
    ...clipboard,

    // Undo/Redo
    undo: historyManager.undo,
    redo: historyManager.redo,
    canUndo: historyManager.canUndo,
    canRedo: historyManager.canRedo,

    // 정렬
    ...alignment,

    // 레이어/잠금/그룹
    ...layer,

    // 메뉴 연결
    menuObjids,
    setMenuObjids,

    // 쿼리 관리
    ...queryManager,
  };

  return (
    <ReportDesignerContext.Provider value={value}>
      {children}
    </ReportDesignerContext.Provider>
  );
}

/**
 * 리포트 디자이너 Context를 소비하는 훅.
 * ReportDesignerProvider 내부에서만 사용 가능하다.
 */
export function useReportDesigner() {
  const context = useContext(ReportDesignerContext);
  if (context === undefined) {
    throw new Error("useReportDesigner must be used within a ReportDesignerProvider");
  }
  return context;
}
