#!/usr/bin/env node

import { readFileSync } from "fs";
import { dirname, join } from "path";
import { fileURLToPath } from "url";

// Get the directory containing this script
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Types for our game data (same as main server)
interface Entity {
  id: string;
  name: string;
  slug: string;
  type: string;
  faction: string;
  tags: string[];
  description?: string;
  lore?: string;
  tier?: string;
  health?: number;
  shields?: number;
  attack?: number;
  armor?: number;
  speed?: number;
  supply?: number;
  flux?: number;
  buildTime?: number;
}

interface TagInfo {
  tag: string;
  label: string;
  description: string;
  slug: string;
}

interface GameData {
  entities: Entity[];
  tags: Record<string, TagInfo>;
  entitiesByFaction: Record<string, Entity[]>;
  entitiesByType: Record<string, Entity[]>;
  entitiesById: Record<string, Entity>;
  mechanics?: any;
}

// Load game data from iolin JSON files
function loadGameData(): GameData {
  const iolinPath = join(__dirname, "../../iolin/dist/json");

  try {
    // Load all entities
    const allData = JSON.parse(readFileSync(join(iolinPath, "all.json"), "utf8"));
    const tagsData = JSON.parse(readFileSync(join(iolinPath, "tags.json"), "utf8"));

    // Load mechanics data
    let mechanicsData = null;
    try {
      mechanicsData = JSON.parse(readFileSync(join(iolinPath, "meta/mechanics.json"), "utf8"));
    } catch (mechanicsError) {
      console.error("⚠️  Could not load mechanics data:", mechanicsError);
    }

    // Build our structured data
    const entities: Entity[] = [];
    const entitiesByFaction: Record<string, Entity[]> = {};
    const entitiesByType: Record<string, Entity[]> = {};
    const entitiesById: Record<string, Entity> = {};

    // Process entities from all.json
    for (const [category, categoryData] of Object.entries(allData)) {
      if (typeof categoryData === "object" && categoryData !== null) {
        for (const [key, entityData] of Object.entries(categoryData as Record<string, any>)) {
          if (typeof entityData === "object" && entityData !== null && "id" in entityData) {
            const entity: Entity = {
              id: entityData.id || key,
              name: entityData.name || key,
              slug: entityData.slug || key,
              type: entityData.type || category,
              faction: entityData.faction || "unknown",
              tags: Array.isArray(entityData.tags) ? entityData.tags : [],
              description: entityData.description,
              lore: entityData.lore,
              tier: entityData.tier,
              health: typeof entityData.health === "number" ? entityData.health : undefined,
              shields: typeof entityData.shields === "number" ? entityData.shields : undefined,
              attack: typeof entityData.attack === "number" ? entityData.attack : undefined,
              armor: typeof entityData.armor === "number" ? entityData.armor : undefined,
              speed: typeof entityData.speed === "number" ? entityData.speed : undefined,
              supply: typeof entityData.supply === "number" ? entityData.supply : undefined,
              flux: typeof entityData.flux === "number" ? entityData.flux : undefined,
              buildTime:
                typeof entityData.buildTime === "number" ? entityData.buildTime : undefined,
            };

            entities.push(entity);
            entitiesById[entity.id] = entity;

            // Group by faction
            if (!entitiesByFaction[entity.faction]) {
              entitiesByFaction[entity.faction] = [];
            }
            entitiesByFaction[entity.faction]!.push(entity);

            // Group by type
            if (!entitiesByType[entity.type]) {
              entitiesByType[entity.type] = [];
            }
            entitiesByType[entity.type]!.push(entity);
          }
        }
      }
    }

    return {
      entities,
      tags: tagsData.tags || {},
      entitiesByFaction,
      entitiesByType,
      entitiesById,
      mechanics: mechanicsData,
    };
  } catch (error) {
    console.error("Failed to load game data:", error);
    process.exit(1);
  }
}

// CLI Commands
function showHelp() {
  console.log(`
Anrubic CLI - ZeroSpace Game Data Tool

Usage: anrubic <command> [options]

Commands:
  status                    Show server status and data statistics
  tags                      List all available tags
  factions                  List all factions with entity counts
  faction <name>            Show all entities for a faction
  search <query> [limit]    Search entities by name/description/tags
  get <id>                  Get entity details by ID
  types                     List all entity types
  type <name>               Show all entities of a specific type
  ids [type] [faction]      List all entity IDs (optionally filtered)
  mechanics [term]          Show game mechanics (all or specific term)

Examples:
  anrubic status
  anrubic tags
  anrubic faction "Terran Alliance"
  anrubic search marine 5
  anrubic get marine
  anrubic type unit
  anrubic ids unit "Xol Collective"
  anrubic mechanics
  anrubic mechanics ABES
  anrubic mechanics Infuse

🚀 ZeroSpace.gg - Cosmic Data Empire
`);
}

function formatEntity(entity: Entity, detailed = false): string {
  let output = `${entity.name} (${entity.id})`;

  if (detailed) {
    output += `\n  Type: ${entity.type}`;
    output += `\n  Faction: ${entity.faction}`;
    if (entity.description) output += `\n  Description: ${entity.description}`;
    if (entity.lore) output += `\n  Lore: ${entity.lore}`;
    if (entity.tier) output += `\n  Tier: ${entity.tier}`;
    if (entity.health) output += `\n  Health: ${entity.health}`;
    if (entity.shields) output += `\n  Shields: ${entity.shields}`;
    if (entity.attack) output += `\n  Attack: ${entity.attack}`;
    if (entity.armor) output += `\n  Armor: ${entity.armor}`;
    if (entity.speed) output += `\n  Speed: ${entity.speed}`;
    if (entity.supply) output += `\n  Supply: ${entity.supply}`;
    if (entity.flux) output += `\n  Flux: ${entity.flux}`;
    if (entity.buildTime) output += `\n  Build Time: ${entity.buildTime}s`;
    if (entity.tags.length > 0) output += `\n  Tags: ${entity.tags.join(", ")}`;
  } else {
    output += ` [${entity.type}/${entity.faction}]`;
  }

  return output;
}

// Parse command line arguments
const args = process.argv.slice(2);
const command = args[0];
const isJsonOutput = args.includes('--json');

// Initialize game data
if (!isJsonOutput) {
  console.error("Loading ZeroSpace game data...");
}
const gameData = loadGameData();
if (!isJsonOutput) {
  console.error(
    `Loaded ${gameData.entities.length} entities from ${Object.keys(gameData.entitiesByFaction).length} factions`,
  );
}

switch (command) {
  case "status":
    console.log("🚀 Anrubic Status");
    console.log("================");
    console.log(`Entities: ${gameData.entities.length}`);
    console.log(`Factions: ${Object.keys(gameData.entitiesByFaction).length}`);
    console.log(`Types: ${Object.keys(gameData.entitiesByType).length}`);
    console.log(`Tags: ${Object.keys(gameData.tags).length}`);
    const basicCount = gameData.mechanics?.mechanics?.basicMechanics
      ? Object.keys(gameData.mechanics.mechanics.basicMechanics).length
      : 0;
    const transformCount = gameData.mechanics?.mechanics?.transformations
      ? Object.keys(gameData.mechanics.mechanics.transformations).length
      : 0;
    console.log(`Mechanics: ${basicCount} basic, ${transformCount} transformations`);
    console.log(`Timestamp: ${new Date().toISOString()}`);
    break;

  case "tags":
    console.log("🏷️  Available Tags");
    console.log("=================");
    for (const [tag, info] of Object.entries(gameData.tags)) {
      console.log(`${tag}: ${info.label}`);
      if (info.description && info.description !== info.label) {
        console.log(`  ${info.description}`);
      }
    }
    break;

  case "factions":
    console.log("🏛️  Available Factions");
    console.log("====================");
    for (const [faction, entities] of Object.entries(gameData.entitiesByFaction)) {
      console.log(`${faction}: ${entities.length} entities`);
    }
    break;

  case "faction":
    const factionName = args[1];
    if (!factionName) {
      console.error("Please specify a faction name");
      console.error("Available factions:", Object.keys(gameData.entitiesByFaction).join(", "));
      process.exit(1);
    }

    const factionEntities = gameData.entitiesByFaction[factionName];
    if (!factionEntities) {
      console.error(`Faction "${factionName}" not found`);
      console.error("Available factions:", Object.keys(gameData.entitiesByFaction).join(", "));
      process.exit(1);
    }

    console.log(`🏛️  ${factionName} (${factionEntities.length} entities)`);
    console.log("=".repeat(factionName.length + 20));

    // Group by type
    const factionByType: Record<string, Entity[]> = {};
    for (const entity of factionEntities) {
      if (!factionByType[entity.type]) {
        factionByType[entity.type] = [];
      }
      factionByType[entity.type]!.push(entity);
    }

    for (const [type, entities] of Object.entries(factionByType)) {
      console.log(`\n${type.toUpperCase()}S:`);
      for (const entity of entities) {
        console.log(`  ${formatEntity(entity)}`);
      }
    }
    break;

  case "search":
    const query = args[1];
    const limit = parseInt(args[2] || "10") || 10;

    if (!query) {
      console.error("Please specify a search query");
      process.exit(1);
    }

    const lowerQuery = query.toLowerCase();
    const matches = gameData.entities
      .filter(
        (entity) =>
          entity.name.toLowerCase().includes(lowerQuery) ||
          entity.description?.toLowerCase().includes(lowerQuery) ||
          entity.lore?.toLowerCase().includes(lowerQuery) ||
          entity.tags.some((tag) => tag.toLowerCase().includes(lowerQuery)),
      )
      .slice(0, limit);

    console.log(`🔍 Search Results for "${query}" (${matches.length} matches)`);
    console.log("=".repeat(30 + query.length));

    if (matches.length === 0) {
      console.log("No matches found");
    } else {
      for (const entity of matches) {
        console.log(`  ${formatEntity(entity)}`);
      }
    }
    break;

  case "get":
    const entityId = args[1];
    if (!entityId) {
      if (isJsonOutput) {
        console.log(JSON.stringify({ error: "Please specify an entity ID" }, null, 2));
      } else {
        console.error("Please specify an entity ID");
      }
      process.exit(1);
    }

    const entity = gameData.entitiesById[entityId];
    if (!entity) {
      if (isJsonOutput) {
        console.log(JSON.stringify({ error: `Entity "${entityId}" not found` }, null, 2));
      } else {
        console.error(`Entity "${entityId}" not found`);
      }
      process.exit(1);
    }

    if (isJsonOutput) {
      console.log(JSON.stringify(entity, null, 2));
    } else {
      console.log(`Entity Details: ${entity.name}`);
      console.log("=".repeat(20 + entity.name.length));
      console.log(formatEntity(entity, true));
    }
    break;

  case "types":
    console.log("📦 Available Types");
    console.log("=================");
    for (const [type, entities] of Object.entries(gameData.entitiesByType)) {
      console.log(`${type}: ${entities.length} entities`);
    }
    break;

  case "type":
    const typeName = args[1];
    if (!typeName) {
      console.error("Please specify a type name");
      console.error("Available types:", Object.keys(gameData.entitiesByType).join(", "));
      process.exit(1);
    }

    const typeEntities = gameData.entitiesByType[typeName];
    if (!typeEntities) {
      console.error(`Type "${typeName}" not found`);
      console.error("Available types:", Object.keys(gameData.entitiesByType).join(", "));
      process.exit(1);
    }

    console.log(`📦 ${typeName.toUpperCase()} (${typeEntities.length} entities)`);
    console.log("=".repeat(typeName.length + 20));

    for (const entity of typeEntities) {
      console.log(`  ${formatEntity(entity)}`);
    }
    break;

  case "ids":
    const filterType = args[1];
    const filterFaction = args[2];

    let filteredEntities = gameData.entities;

    if (filterType) {
      filteredEntities = filteredEntities.filter((e) => e.type === filterType);
    }
    if (filterFaction) {
      filteredEntities = filteredEntities.filter((e) => e.faction === filterFaction);
    }

    console.log(`🆔 Entity IDs (${filteredEntities.length} total)`);
    if (filterType || filterFaction) {
      console.log(
        `Filters: ${filterType ? `type=${filterType}` : ""}${filterType && filterFaction ? ", " : ""}${filterFaction ? `faction=${filterFaction}` : ""}`,
      );
    }
    console.log("=".repeat(30));

    for (const entity of filteredEntities) {
      console.log(`${entity.id} - ${entity.name} [${entity.type}/${entity.faction}]`);
    }
    break;

  case "mechanics":
    const mechanicTerm = args[1];

    if (!gameData.mechanics) {
      console.error("Mechanics data not available");
      process.exit(1);
    }

    // Flatten hierarchical mechanics for search
    const allMechanics: Record<string, any> = {};
    if (gameData.mechanics.mechanics?.basicMechanics) {
      Object.assign(allMechanics, gameData.mechanics.mechanics.basicMechanics);
    }
    if (gameData.mechanics.mechanics?.transformations) {
      Object.assign(allMechanics, gameData.mechanics.mechanics.transformations);
    }

    if (mechanicTerm) {
      // Show specific mechanic
      const mechanic = allMechanics[mechanicTerm];
      if (!mechanic) {
        console.error(`Mechanic "${mechanicTerm}" not found`);
        console.error("Available mechanics:", Object.keys(allMechanics).join(", "));
        process.exit(1);
      }

      console.log(`Mechanic: ${mechanic.term || mechanic.name}`);
      console.log("=".repeat(15 + (mechanic.term || mechanic.name).length));

      if (mechanic.term) {
        // Basic mechanic
        console.log(`Keywords: ${mechanic.keywords?.join(", ") || "None"}`);
        console.log(`Description: ${mechanic.description || "No description"}`);
      } else if (mechanic.name) {
        // Transformation
        console.log(`Type: ${mechanic.type}`);
        console.log(`Keywords: ${mechanic.keywords?.join(", ") || "None"}`);
        console.log(`Description: ${mechanic.description || "No description"}`);
        console.log(
          `Stackable: ${mechanic.stackable ? "Yes" : "No"}${mechanic.maxStacks ? ` (max ${mechanic.maxStacks})` : ""}`,
        );

        if (mechanic.statModifications) {
          console.log("\nStat Modifications:");
          if (mechanic.statModifications.hpMultiplier) {
            console.log(`  HP: ${mechanic.statModifications.hpMultiplier}x`);
          }
          if (mechanic.statModifications.damageMultiplier) {
            console.log(`  Damage: ${mechanic.statModifications.damageMultiplier}x`);
          }
        }

        if (mechanic.hasPhases && (mechanic.preDeathPhase || mechanic.postDeathPhase)) {
          console.log("\nPhases:");
          if (mechanic.preDeathPhase) {
            console.log(
              `  Pre-death: Speed ${mechanic.preDeathPhase.speedMultiplier}x, Cooldowns ${mechanic.preDeathPhase.cooldownMultiplier}x`,
            );
          }
          if (mechanic.postDeathPhase) {
            console.log(
              `  Post-death: Speed ${mechanic.postDeathPhase.speedMultiplier}x, Cooldowns ${mechanic.postDeathPhase.cooldownMultiplier}x`,
            );
          }
        }

        if (mechanic.notes) {
          console.log(`\nNotes: ${mechanic.notes}`);
        }
      }
    } else {
      // Show all mechanics
      const basicCount = gameData.mechanics.mechanics?.basicMechanics
        ? Object.keys(gameData.mechanics.mechanics.basicMechanics).length
        : 0;
      const transformCount = gameData.mechanics.mechanics?.transformations
        ? Object.keys(gameData.mechanics.mechanics.transformations).length
        : 0;

      console.log(`ZeroSpace Game Mechanics (${basicCount + transformCount} total)`);
      console.log("===============================");
      console.log(`${basicCount} basic mechanics, ${transformCount} transformations\n`);

      if (gameData.mechanics.mechanics?.basicMechanics) {
        console.log("BASIC MECHANICS:");
        for (const [key, mechanic] of Object.entries(gameData.mechanics.mechanics.basicMechanics)) {
          const typedMechanic = mechanic as { term?: string; description?: string };
          console.log(
            `  ${typedMechanic.term || key} - ${(typedMechanic.description || "").substring(0, 80)}${(typedMechanic.description || "").length > 80 ? "..." : ""}`,
          );
        }
        console.log();
      }

      if (gameData.mechanics.mechanics?.transformations) {
        console.log("TRANSFORMATIONS:");
        for (const [key, transformation] of Object.entries(
          gameData.mechanics.mechanics.transformations,
        )) {
          const typedTransformation = transformation as { name?: string; description?: string };
          console.log(
            `  ${typedTransformation.name || key} - ${(typedTransformation.description || "").substring(0, 80)}${(typedTransformation.description || "").length > 80 ? "..." : ""}`,
          );
        }
      }
    }
    break;

  case "help":
  case "--help":
  case "-h":
    showHelp();
    break;

  default:
    if (!command) {
      showHelp();
    } else {
      console.error(`Unknown command: ${command}`);
      showHelp();
      process.exit(1);
    }
}
