// import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { vi } from "vitest";
import { SheetViewer } from "../SheetViewer";
import { useAppStore } from "../../../stores/useAppStore";
import type { SheetData } from "../../../types/sheet";

// Mock dependencies
vi.mock("../../../stores/useAppStore");

// Luckysheet 모킹
const mockLuckysheet = {
  create: vi.fn(),
  destroy: vi.fn(),
  resize: vi.fn(),
  getSheet: vi.fn(),
  getAllSheets: vi.fn(),
  setActiveSheet: vi.fn(),
};

// Window.luckysheet 모킹
Object.defineProperty(window, "luckysheet", {
  value: mockLuckysheet,
  writable: true,
});

// useAppStore 모킹 타입
const mockUseAppStore = vi.mocked(useAppStore);

// 기본 스토어 상태
const defaultStoreState = {
  sheets: [],
  activeSheetId: null,
  currentFile: null,
  setSelectedRange: vi.fn(),
  isLoading: false,
  error: null,
  setLoading: vi.fn(),
  setError: vi.fn(),
  uploadFile: vi.fn(),
  clearFileUploadErrors: vi.fn(),
  resetApp: vi.fn(),
};

// 테스트용 시트 데이터
const mockSheetData: SheetData[] = [
  {
    id: "sheet_0",
    name: "Sheet1",
    data: [
      ["A1", "B1", "C1"],
      ["A2", "B2", "C2"],
    ],
    config: {
      container: "luckysheet_0",
      title: "Sheet1",
      lang: "ko",
      data: [
        {
          name: "Sheet1",
          index: "0",
          celldata: [
            {
              r: 0,
              c: 0,
              v: { v: "A1", m: "A1", ct: { fa: "General", t: "g" } },
            },
            {
              r: 0,
              c: 1,
              v: { v: "B1", m: "B1", ct: { fa: "General", t: "g" } },
            },
          ],
          status: 1,
          order: 0,
          row: 2,
          column: 3,
        },
      ],
      options: {
        showtoolbar: true,
        showinfobar: false,
        showsheetbar: true,
        showstatisticBar: false,
        allowCopy: true,
        allowEdit: true,
        enableAddRow: true,
        enableAddCol: true,
      },
    },
  },
];

describe("SheetViewer", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockUseAppStore.mockReturnValue(defaultStoreState);
  });

  afterEach(() => {
    // DOM 정리
    document.head.innerHTML = "";
  });

  describe("초기 렌더링", () => {
    it("시트 데이터가 없을 때 적절한 메시지를 표시한다", () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: [],
      });

      render(<SheetViewer />);

      expect(screen.getByText("표시할 시트가 없습니다")).toBeInTheDocument();
      expect(
        screen.getByText("Excel 파일을 업로드해주세요."),
      ).toBeInTheDocument();
    });

    it("시트 데이터가 있을 때 로딩 상태를 표시한다", () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      render(<SheetViewer />);

      expect(screen.getByText("시트 로딩 중...")).toBeInTheDocument();
      expect(screen.getByText("잠시만 기다려주세요.")).toBeInTheDocument();
    });

    it("Luckysheet 컨테이너가 올바르게 렌더링된다", () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      render(<SheetViewer />);

      const container = document.getElementById("luckysheet-container");
      expect(container).toBeInTheDocument();
      expect(container).toHaveClass("w-full", "h-full");
    });
  });

  describe("Luckysheet 초기화", () => {
    it("시트 데이터가 변경되면 Luckysheet를 초기화한다", async () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      render(<SheetViewer />);

      await waitFor(() => {
        expect(mockLuckysheet.create).toHaveBeenCalled();
      });

      // create 호출 시 전달된 설정 확인
      const createCall = mockLuckysheet.create.mock.calls[0];
      expect(createCall).toBeDefined();

      const config = createCall[0];
      expect(config.container).toBe("luckysheet-container");
      expect(config.title).toBe("test.xlsx");
      expect(config.lang).toBe("ko");
      expect(config.data).toHaveLength(1);
    });

    it("기존 Luckysheet 인스턴스가 있으면 제거한다", async () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      const { rerender } = render(<SheetViewer />);

      await waitFor(() => {
        expect(mockLuckysheet.create).toHaveBeenCalledTimes(1);
      });

      // 시트 데이터 변경
      const newSheetData: SheetData[] = [
        {
          ...mockSheetData[0],
          name: "NewSheet",
        },
      ];

      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: newSheetData,
        currentFile: { name: "new.xlsx", size: 1000, uploadedAt: new Date() },
      });

      rerender(<SheetViewer />);

      await waitFor(() => {
        expect(mockLuckysheet.destroy).toHaveBeenCalled();
        expect(mockLuckysheet.create).toHaveBeenCalledTimes(2);
      });
    });
  });

  describe("에러 처리", () => {
    it("Luckysheet 초기화 실패 시 에러 메시지를 표시한다", async () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      // Luckysheet.create에서 에러 발생 시뮬레이션
      mockLuckysheet.create.mockImplementation(() => {
        throw new Error("Luckysheet 초기화 실패");
      });

      render(<SheetViewer />);

      await waitFor(() => {
        expect(screen.getByText("시트 로드 오류")).toBeInTheDocument();
        expect(
          screen.getByText(/시트 초기화에 실패했습니다/),
        ).toBeInTheDocument();
      });

      // 다시 시도 버튼 확인
      const retryButton = screen.getByRole("button", { name: "다시 시도" });
      expect(retryButton).toBeInTheDocument();
    });

    it("다시 시도 버튼을 클릭하면 초기화를 재시도한다", async () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      // 첫 번째 시도에서 실패
      mockLuckysheet.create.mockImplementationOnce(() => {
        throw new Error("첫 번째 실패");
      });

      render(<SheetViewer />);

      await waitFor(() => {
        expect(screen.getByText("시트 로드 오류")).toBeInTheDocument();
      });

      // 두 번째 시도에서 성공하도록 설정
      mockLuckysheet.create.mockImplementationOnce(() => {
        // 성공
      });

      const retryButton = screen.getByRole("button", { name: "다시 시도" });
      retryButton.click();

      await waitFor(() => {
        expect(mockLuckysheet.create).toHaveBeenCalledTimes(2);
      });
    });
  });

  describe("이벤트 핸들링", () => {
    it("셀 클릭 시 선택된 범위를 스토어에 저장한다", async () => {
      const mockSetSelectedRange = vi.fn();
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
        setSelectedRange: mockSetSelectedRange,
      });

      render(<SheetViewer />);

      await waitFor(() => {
        expect(mockLuckysheet.create).toHaveBeenCalled();
      });

      // create 호출 시 전달된 hook 확인
      const createCall = mockLuckysheet.create.mock.calls[0];
      const config = createCall[0];

      // cellClick 핸들러 시뮬레이션
      const cellClickHandler = config.hook.cellClick;
      expect(cellClickHandler).toBeDefined();

      const mockCell = {};
      const mockPosition = { r: 1, c: 2 };
      const mockSheetFile = { index: "0" };

      cellClickHandler(mockCell, mockPosition, mockSheetFile);

      expect(mockSetSelectedRange).toHaveBeenCalledWith({
        range: {
          startRow: 1,
          startCol: 2,
          endRow: 1,
          endCol: 2,
        },
        sheetId: "0",
      });
    });

    it("시트 활성화 시 활성 시트 ID를 업데이트한다", async () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      // setActiveSheetId를 spy로 설정
      const setActiveSheetIdSpy = vi.fn();
      useAppStore.getState = vi.fn().mockReturnValue({
        setActiveSheetId: setActiveSheetIdSpy,
      });

      render(<SheetViewer />);

      await waitFor(() => {
        expect(mockLuckysheet.create).toHaveBeenCalled();
      });

      // create 호출 시 전달된 hook 확인
      const createCall = mockLuckysheet.create.mock.calls[0];
      const config = createCall[0];

      // sheetActivate 핸들러 시뮬레이션
      const sheetActivateHandler = config.hook.sheetActivate;
      expect(sheetActivateHandler).toBeDefined();

      sheetActivateHandler(0, false, false);

      expect(setActiveSheetIdSpy).toHaveBeenCalledWith("sheet_0");
    });
  });

  describe("컴포넌트 생명주기", () => {
    it("컴포넌트 언마운트 시 Luckysheet를 정리한다", async () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      const { unmount } = render(<SheetViewer />);

      await waitFor(() => {
        expect(mockLuckysheet.create).toHaveBeenCalled();
      });

      unmount();

      expect(mockLuckysheet.destroy).toHaveBeenCalled();
    });

    it("윈도우 리사이즈 시 Luckysheet 리사이즈를 호출한다", async () => {
      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      render(<SheetViewer />);

      await waitFor(() => {
        expect(mockLuckysheet.create).toHaveBeenCalled();
      });

      // 윈도우 리사이즈 이벤트 시뮬레이션
      window.dispatchEvent(new Event("resize"));

      expect(mockLuckysheet.resize).toHaveBeenCalled();
    });
  });

  describe("개발 모드 정보", () => {
    it("개발 모드에서 시트 정보를 표시한다", () => {
      const originalEnv = process.env.NODE_ENV;
      process.env.NODE_ENV = "development";

      mockUseAppStore.mockReturnValue({
        ...defaultStoreState,
        sheets: mockSheetData,
        activeSheetId: "sheet_0",
        currentFile: { name: "test.xlsx", size: 1000, uploadedAt: new Date() },
      });

      render(<SheetViewer />);

      expect(screen.getByText("시트 개수: 1")).toBeInTheDocument();
      expect(screen.getByText("활성 시트: sheet_0")).toBeInTheDocument();

      process.env.NODE_ENV = originalEnv;
    });
  });
});
