import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useGameModals } from "../useGameModals";
import { GAME_STATES } from "../../contexts/GameStateContext";

// Parâmetros padrão reutilizados nos testes
const DEFAULT_PHASE_CONFIG = { maxBlocks: 10 };
const DEFAULT_GAME_CONFIG = { fases: [1, 2, 3] }; // 3 fases

function buildOptions(overrides = {}) {
  return {
    executionState: GAME_STATES.PARADO,
    currentPhase: 1,
    phaseConfig: DEFAULT_PHASE_CONFIG,
    gameConfig: DEFAULT_GAME_CONFIG,
    setCurrentPhase: vi.fn(),
    restart: vi.fn(),
    setOnWorkspaceChange: vi.fn(),
    usaModalFalha: false,
    ...overrides,
  };
}

// ---------------------------------------------------------------------------
describe("useGameModals — estado inicial", () => {
  it("todos os modais começam fechados", () => {
    const { result } = renderHook(() => useGameModals(buildOptions()));

    expect(result.current.modalFasesAberto).toBe(false);
    expect(result.current.modalSucessoAberto).toBe(false);
    expect(result.current.modalFalhaAberto).toBe(false);
  });

  it("contagens de blocos começam como null", () => {
    const { result } = renderHook(() => useGameModals(buildOptions()));

    expect(result.current.blocksRemainingCount).toBeNull();
  });
});

// ---------------------------------------------------------------------------
describe("useGameModals — abertura automática de modais", () => {
  it("abre modal de sucesso quando executionState muda para SUCESSO", () => {
    const options = buildOptions({ executionState: GAME_STATES.SUCESSO });
    const { result } = renderHook(() => useGameModals(options));

    expect(result.current.modalSucessoAberto).toBe(true);
  });

  it("abre modal de falha quando executionState é FALHA e usaModalFalha=true", () => {
    const options = buildOptions({
      executionState: GAME_STATES.FALHA,
      usaModalFalha: true,
    });
    const { result } = renderHook(() => useGameModals(options));

    expect(result.current.modalFalhaAberto).toBe(true);
  });

  it("NÃO abre modal de falha quando usaModalFalha=false", () => {
    const options = buildOptions({
      executionState: GAME_STATES.FALHA,
      usaModalFalha: false,
    });
    const { result } = renderHook(() => useGameModals(options));

    expect(result.current.modalFalhaAberto).toBe(false);
  });

  it("não abre nenhum modal quando executionState é PARADO", () => {
    const options = buildOptions({ executionState: GAME_STATES.PARADO });
    const { result } = renderHook(() => useGameModals(options));

    expect(result.current.modalSucessoAberto).toBe(false);
    expect(result.current.modalFalhaAberto).toBe(false);
  });
});

// ---------------------------------------------------------------------------
describe("useGameModals — handlers de fechar modais", () => {
  it("handleFecharModalSucesso fecha o modal de sucesso", () => {
    const { result } = renderHook(() =>
      useGameModals(buildOptions({ executionState: GAME_STATES.SUCESSO })),
    );

    expect(result.current.modalSucessoAberto).toBe(true);

    act(() => {
      result.current.handleFecharModalSucesso();
    });

    expect(result.current.modalSucessoAberto).toBe(false);
  });

  it("handleFecharModalFalha fecha o modal de falha", () => {
    const { result } = renderHook(() =>
      useGameModals(
        buildOptions({ executionState: GAME_STATES.FALHA, usaModalFalha: true }),
      ),
    );

    expect(result.current.modalFalhaAberto).toBe(true);

    act(() => {
      result.current.handleFecharModalFalha();
    });

    expect(result.current.modalFalhaAberto).toBe(false);
  });

  it("setModalFasesAberto abre e fecha o modal de fases", () => {
    const { result } = renderHook(() => useGameModals(buildOptions()));

    act(() => {
      result.current.setModalFasesAberto(true);
    });
    expect(result.current.modalFasesAberto).toBe(true);

    act(() => {
      result.current.setModalFasesAberto(false);
    });
    expect(result.current.modalFasesAberto).toBe(false);
  });
});

// ---------------------------------------------------------------------------
describe("useGameModals — handleTentarNovamente", () => {
  it("fecha o modal de falha e chama restart()", () => {
    const restart = vi.fn();
    const { result } = renderHook(() =>
      useGameModals(
        buildOptions({
          executionState: GAME_STATES.FALHA,
          usaModalFalha: true,
          restart,
        }),
      ),
    );

    act(() => {
      result.current.handleTentarNovamente();
    });

    expect(result.current.modalFalhaAberto).toBe(false);
    expect(restart).toHaveBeenCalledOnce();
  });
});

// ---------------------------------------------------------------------------
describe("useGameModals — handleProximaFase", () => {
  it("avança para a próxima fase, fecha o modal de sucesso e chama restart()", () => {
    const setCurrentPhase = vi.fn();
    const restart = vi.fn();
    const { result } = renderHook(() =>
      useGameModals(
        buildOptions({
          executionState: GAME_STATES.SUCESSO,
          currentPhase: 1,
          setCurrentPhase,
          restart,
        }),
      ),
    );

    act(() => {
      result.current.handleProximaFase();
    });

    expect(setCurrentPhase).toHaveBeenCalledWith(2);
    expect(result.current.modalSucessoAberto).toBe(false);
    expect(restart).toHaveBeenCalledOnce();
  });

  it("não avança além da última fase", () => {
    const setCurrentPhase = vi.fn();
    const { result } = renderHook(() =>
      useGameModals(
        buildOptions({
          currentPhase: 3, // última fase (gameConfig tem 3 fases)
          setCurrentPhase,
        }),
      ),
    );

    act(() => {
      result.current.handleProximaFase();
    });

    expect(setCurrentPhase).not.toHaveBeenCalled();
  });
});

// ---------------------------------------------------------------------------
describe("useGameModals — workspace change callback", () => {
  it("registra o callback de workspace na montagem", () => {
    const setOnWorkspaceChange = vi.fn();
    renderHook(() => useGameModals(buildOptions({ setOnWorkspaceChange })));

    expect(setOnWorkspaceChange).toHaveBeenCalledWith(expect.any(Function));
  });

  it("remove o callback de workspace na desmontagem", () => {
    const setOnWorkspaceChange = vi.fn();
    const { unmount } = renderHook(() =>
      useGameModals(buildOptions({ setOnWorkspaceChange })),
    );

    unmount();

    expect(setOnWorkspaceChange).toHaveBeenLastCalledWith(null);
  });

  it("calcula blocos restantes corretamente", () => {
    const setOnWorkspaceChange = vi.fn();
    const { result } = renderHook(() =>
      useGameModals(
        buildOptions({
          phaseConfig: { maxBlocks: 10 },
          setOnWorkspaceChange,
        }),
      ),
    );

    // Obtém o callback registrado e invoca-o
    const registeredCallback = setOnWorkspaceChange.mock.calls[0][0];
    act(() => {
      registeredCallback(4);
    });

    expect(result.current.blocksRemainingCount).toBe(6);
  });

  it("mantém blocos null quando maxBlocks é Infinity", () => {
    const setOnWorkspaceChange = vi.fn();
    const { result } = renderHook(() =>
      useGameModals(
        buildOptions({
          phaseConfig: { maxBlocks: Infinity },
          setOnWorkspaceChange,
        }),
      ),
    );

    const registeredCallback = setOnWorkspaceChange.mock.calls[0][0];
    act(() => {
      registeredCallback(5);
    });

    expect(result.current.blocksRemainingCount).toBeNull();
  });

  it("trata blockCount não-numérico como 0", () => {
    const setOnWorkspaceChange = vi.fn();
    const { result } = renderHook(() =>
      useGameModals(
        buildOptions({
          phaseConfig: { maxBlocks: 8 },
          setOnWorkspaceChange,
        }),
      ),
    );

    const registeredCallback = setOnWorkspaceChange.mock.calls[0][0];
    act(() => {
      registeredCallback("não-número");
    });

    expect(result.current.blocksRemainingCount).toBe(8);
  });

  it("não lança erro quando setOnWorkspaceChange é undefined", () => {
    expect(() =>
      renderHook(() =>
        useGameModals(buildOptions({ setOnWorkspaceChange: undefined })),
      ),
    ).not.toThrow();
  });
});
