import { describe, it, expect, afterEach } from "vitest";
import {
  GAMES_REGISTRY,
  GAME_REGISTRY,
  gameRegistryUtils,
  getGameConfig,
  getAllGames,
  registerGame,
} from "../gameRegistry";

const EXPECTED_IDS = [
  "aspirador",
  "automato",
  "cripto",
  "molemash",
  "puzzle",
  "semaforo",
  "turtle",
];

describe("GAMES_REGISTRY — estrutura", () => {
  it("contem todos os 7 jogos esperados", () => {
    expect(Object.keys(GAMES_REGISTRY)).toEqual(expect.arrayContaining(EXPECTED_IDS));
    expect(Object.keys(GAMES_REGISTRY)).toHaveLength(EXPECTED_IDS.length);
  });

  it("cada jogo tem os campos obrigatorios", () => {
    Object.entries(GAMES_REGISTRY).forEach(([id, config]) => {
      expect(config.gameId, `${id} deve ter gameId`).toBeDefined();
      expect(config.gameName, `${id} deve ter gameName`).toBeDefined();
      expect(config.descricao, `${id} deve ter descricao`).toBeDefined();
      expect(config.categoria, `${id} deve ter categoria`).toBeDefined();
      expect(config.dificuldade, `${id} deve ter dificuldade`).toBeDefined();
    });
  });

  it("gameId de cada entrada bate com a chave do registry", () => {
    Object.entries(GAMES_REGISTRY).forEach(([key, config]) => {
      expect(config.gameId).toBe(key);
    });
  });

  it("GAME_REGISTRY e alias de GAMES_REGISTRY", () => {
    expect(GAME_REGISTRY).toBe(GAMES_REGISTRY);
  });

  it("configs sao referencias diretas — sem loadGameConfig wrapper", () => {
    expect(typeof GAMES_REGISTRY.aspirador).toBe("object");
    expect(GAMES_REGISTRY.aspirador).not.toBeNull();
  });
});

describe("getGameConfig()", () => {
  it("retorna config de jogo existente", () => {
    const config = getGameConfig("aspirador");
    expect(config.gameId).toBe("aspirador");
  });

  it("lanca erro quando jogo nao existe", () => {
    expect(() => getGameConfig("inexistente")).toThrow(/inexistente/);
  });

  it("lanca erro para ID vazio", () => {
    expect(() => getGameConfig("")).toThrow();
  });
});

describe("getAllGames()", () => {
  it("retorna array com todos os 7 jogos", () => {
    const games = getAllGames();
    expect(games).toHaveLength(EXPECTED_IDS.length);
  });

  it("retorna array de objetos com gameId", () => {
    getAllGames().forEach((g) => {
      expect(g.gameId).toBeDefined();
    });
  });
});

describe("registerGame()", () => {
  afterEach(() => {
    delete GAMES_REGISTRY["test_game"];
  });

  it("registra um novo jogo e o torna acessivel via getGameConfig", () => {
    const fakeGame = { gameId: "test_game", gameName: "Teste" };
    const returned = registerGame(fakeGame);
    expect(returned).toBe(fakeGame);
    expect(getGameConfig("test_game")).toBe(fakeGame);
  });

  it("lanca erro quando gameId esta ausente", () => {
    expect(() => registerGame({ gameName: "Sem ID" })).toThrow(/gameId/);
  });
});

describe("gameRegistryUtils", () => {
  describe("getActiveGames()", () => {
    it("retorna todos os jogos", () => {
      expect(gameRegistryUtils.getActiveGames()).toHaveLength(EXPECTED_IDS.length);
    });
  });

  describe("getFeaturedGames()", () => {
    it("retorna todos os jogos", () => {
      expect(gameRegistryUtils.getFeaturedGames()).toHaveLength(EXPECTED_IDS.length);
    });
  });

  describe("getGameById()", () => {
    it("retorna config quando id existe", () => {
      const g = gameRegistryUtils.getGameById("turtle");
      expect(g.gameId).toBe("turtle");
    });

    it("retorna undefined quando id nao existe", () => {
      expect(gameRegistryUtils.getGameById("xxx")).toBeUndefined();
    });
  });

  describe("getGamesByCategory()", () => {
    it("retorna apenas jogos da categoria pedida", () => {
      const logicaGames = gameRegistryUtils.getGamesByCategory("Logica");
      logicaGames.forEach((g) => expect(g.categoria).toBe("Logica"));
    });

    it("retorna array vazio para categoria inexistente", () => {
      expect(gameRegistryUtils.getGamesByCategory("Categoria Inexistente")).toHaveLength(0);
    });
  });

  describe("getGamesByDifficulty()", () => {
    it("retorna apenas jogos com a dificuldade pedida", () => {
      const games = gameRegistryUtils.getGamesByDifficulty("Iniciante");
      games.forEach((g) => expect(g.dificuldade).toBe("Iniciante"));
    });
  });

  describe("searchGames()", () => {
    it("encontra jogo pelo nome (case-insensitive)", () => {
      const results = gameRegistryUtils.searchGames("aspirador");
      expect(results.some((g) => g.gameId === "aspirador")).toBe(true);
    });

    it("retorna array vazio para query sem match", () => {
      expect(gameRegistryUtils.searchGames("zzzzz_inexistente_zzzzz")).toHaveLength(0);
    });
  });

  describe("registerGame() / unregisterGame() / updateGame()", () => {
    afterEach(() => {
      delete GAMES_REGISTRY["util_test"];
    });

    it("registerGame adiciona jogo ao registry", () => {
      gameRegistryUtils.registerGame({ gameId: "util_test", gameName: "X" });
      expect(GAMES_REGISTRY["util_test"]).toBeDefined();
    });

    it("registerGame lanca erro sem id ou gameId", () => {
      expect(() => gameRegistryUtils.registerGame({ gameName: "Sem" })).toThrow();
    });

    it("unregisterGame remove jogo do registry", () => {
      GAMES_REGISTRY["util_test"] = { gameId: "util_test" };
      gameRegistryUtils.unregisterGame("util_test");
      expect(GAMES_REGISTRY["util_test"]).toBeUndefined();
    });

    it("updateGame mescla atualizacoes sobre config existente", () => {
      GAMES_REGISTRY["util_test"] = { gameId: "util_test", gameName: "Old" };
      gameRegistryUtils.updateGame("util_test", { gameName: "New" });
      expect(GAMES_REGISTRY["util_test"].gameName).toBe("New");
      expect(GAMES_REGISTRY["util_test"].gameId).toBe("util_test");
    });

    it("updateGame nao faz nada quando jogo nao existe", () => {
      expect(() => gameRegistryUtils.updateGame("phantom", { x: 1 })).not.toThrow();
    });
  });

  describe("getCategoriesWithCounts()", () => {
    it("retorna objeto com pelo menos uma categoria", () => {
      const cats = gameRegistryUtils.getCategoriesWithCounts();
      expect(Object.keys(cats).length).toBeGreaterThan(0);
    });

    it("cada categoria tem array games com ao menos um jogo", () => {
      const cats = gameRegistryUtils.getCategoriesWithCounts();
      Object.values(cats).forEach((cat) => {
        expect(Array.isArray(cat.games)).toBe(true);
        expect(cat.games.length).toBeGreaterThan(0);
      });
    });
  });
});
