import bcrypt from "bcrypt";
import type { ResultSetHeader, RowDataPacket } from "mysql2";
import db from "./db.js";
import { SEED_ITEMS } from "./seed-items.js";
import { SEED_TALENTS } from "./seed-talents.js";
import { seedSpells } from "./seed-spells.js";

export async function seedDevData(): Promise<void> {
  await seedSpells();

  const [userRows] = await db.execute<RowDataPacket[]>(
    "SELECT COUNT(*) as c FROM users"
  );
  if ((userRows[0] as { c: number }).c > 0) return;

  const passwordHash = await bcrypt.hash("password", 12);

  // Create DM user
  const [dmResult] = await db.execute<ResultSetHeader>(
    "INSERT INTO users (email, username, password_hash) VALUES (?, ?, ?)",
    ["dm@darkwatch.test", "DungeonMaster", passwordHash]
  );
  const dmId = dmResult.insertId;

  // Create Player user
  const [playerResult] = await db.execute<ResultSetHeader>(
    "INSERT INTO users (email, username, password_hash) VALUES (?, ?, ?)",
    ["player@darkwatch.test", "Adventurer", passwordHash]
  );
  const playerId = playerResult.insertId;

  // Create campaign
  const [campaignResult] = await db.execute<ResultSetHeader>(
    "INSERT INTO campaigns (name) VALUES (?)",
    ["Tomb of the Serpent King"]
  );
  const campaignId = campaignResult.insertId;

  // Add DM as dm, player as player
  await db.execute(
    "INSERT IGNORE INTO campaign_members (campaign_id, user_id, role) VALUES (?, ?, 'dm')",
    [campaignId, dmId]
  );
  await db.execute(
    "INSERT IGNORE INTO campaign_members (campaign_id, user_id, role) VALUES (?, ?, 'player')",
    [campaignId, playerId]
  );

  // Create invite token for testing
  await db.execute(
    "INSERT INTO campaign_invites (campaign_id, token, created_by) VALUES (?, ?, ?)",
    [campaignId, "dev-invite-token-abc123", dmId]
  );

  // Seed game_items from seed-items.ts
  for (const item of SEED_ITEMS) {
    await db.execute(
      "INSERT INTO game_items (name, type, slot_count, effects, properties) VALUES (?, ?, ?, ?, ?)",
      [
        item.name,
        item.type,
        item.slot_count,
        JSON.stringify(item.effects),
        JSON.stringify(item.properties),
      ]
    );
  }

  // Seed game_talents from seed-talents.ts
  for (const talent of SEED_TALENTS) {
    await db.execute(
      "INSERT INTO game_talents (name, source, description, effect) VALUES (?, ?, ?, ?)",
      [
        talent.name,
        talent.source,
        talent.description,
        JSON.stringify(talent.effect),
      ]
    );
  }

  async function createCharacter(
    charCampaignId: number,
    userId: number,
    data: {
      name: string; class: string; ancestry: string; level: number; xp: number;
      hp_current: number; hp_max: number; ac: number; alignment: string;
      title: string; background: string; deity: string; languages: string;
      gp: number; sp: number; cp: number; color: string;
    }
  ): Promise<number> {
    const [r] = await db.execute<ResultSetHeader>(
      `INSERT INTO characters
         (campaign_id, user_id, name, class, ancestry, level, xp, hp_current, hp_max,
          ac, alignment, title, background, deity, languages, gp, sp, cp, color)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [charCampaignId, userId, data.name, data.class, data.ancestry, data.level, data.xp,
       data.hp_current, data.hp_max, data.ac, data.alignment, data.title,
       data.background, data.deity, data.languages, data.gp, data.sp, data.cp, data.color]
    );
    return r.insertId;
  }

  async function addStats(charId: number, stats: [string, number][]) {
    for (const [name, value] of stats) {
      await db.execute(
        "INSERT INTO character_stats (character_id, stat_name, value) VALUES (?, ?, ?)",
        [charId, name, value]
      );
    }
  }

  async function addGear(charId: number, items: { name: string; type: string; slot_count: number; properties: string; effects: string }[]) {
    for (const item of items) {
      await db.execute(
        "INSERT INTO character_gear (character_id, name, type, slot_count, properties, effects) VALUES (?, ?, ?, ?, ?, ?)",
        [charId, item.name, item.type, item.slot_count, item.properties, item.effects]
      );
    }
  }

  async function addTalents(charId: number, talents: { name: string; description: string; effect: string }[]) {
    for (const t of talents) {
      await db.execute(
        "INSERT INTO character_talents (character_id, name, description, effect) VALUES (?, ?, ?, ?)",
        [charId, t.name, t.description, t.effect]
      );
    }
  }

  // --- Limpie (player's character 1) ---
  const limpieId = await createCharacter(campaignId, playerId, {
    name: "Limpie", class: "Thief", ancestry: "Goblin", level: 1, xp: 6,
    hp_current: 1, hp_max: 1, ac: 10, alignment: "Lawful", title: "Footpad",
    background: "Chirurgeo", deity: "Madeera the Covenant",
    languages: "Common, Goblin", gp: 8, sp: 0, cp: 0, color: "hsl(45, 60%, 65%)",
  });
  await addStats(limpieId, [["STR",11],["DEX",11],["CON",8],["INT",10],["WIS",14],["CHA",10]]);
  await addGear(limpieId, [
    { name: "Shortsword", type: "weapon", slot_count: 1, properties: "{}", effects: '{"damage":"1d6","melee":true,"stat":"STR"}' },
    { name: "Shortbow", type: "weapon", slot_count: 1, properties: "{}", effects: '{"damage":"1d4","ranged":true,"stat":"DEX","two_handed":true}' },
    { name: "Leather Armor", type: "armor", slot_count: 1, properties: "{}", effects: '{"ac_base":11,"ac_dex":true}' },
    { name: "Shield", type: "armor", slot_count: 1, properties: "{}", effects: '{"ac_bonus":2}' },
    { name: "Arrows (20)", type: "gear", slot_count: 1, properties: "{}", effects: "{}" },
    { name: "Torch", type: "gear", slot_count: 1, properties: "{}", effects: "{}" },
    { name: "Rations", type: "gear", slot_count: 1, properties: "{}", effects: "{}" },
    { name: "Rope (60ft)", type: "gear", slot_count: 1, properties: "{}", effects: "{}" },
    { name: "Thieves' Tools", type: "gear", slot_count: 1, properties: "{}", effects: "{}" },
  ]);
  await addTalents(limpieId, [
    { name: "Backstab", description: "Extra 1 + half level (round down) weapon dice of damage with surprise attacks", effect: '{"damage_bonus_surprise":true}' },
    { name: "Thievery", description: "Trained in climbing, sneaking, hiding, disguise, finding & disabling traps, delicate tasks", effect: "{}" },
    { name: "Keen Senses", description: "Can't be surprised", effect: '{"immune_surprise":true}' },
  ]);

  // --- Brynn (player's character 2) ---
  const brynnId = await createCharacter(campaignId, playerId, {
    name: "Brynn", class: "Fighter", ancestry: "Human", level: 2, xp: 15,
    hp_current: 8, hp_max: 10, ac: 10, alignment: "Neutral", title: "the Bold",
    background: "Soldier", deity: "Gede", languages: "Common",
    gp: 25, sp: 5, cp: 10, color: "hsl(200, 60%, 65%)",
  });
  await addStats(brynnId, [["STR",16],["DEX",12],["CON",14],["INT",8],["WIS",10],["CHA",11]]);
  await addGear(brynnId, [
    { name: "Longsword", type: "weapon", slot_count: 1, properties: "{}", effects: '{"damage":"1d8","melee":true,"stat":"STR"}' },
    { name: "Chainmail", type: "armor", slot_count: 1, properties: "{}", effects: '{"ac_base":13,"ac_dex":true}' },
    { name: "Shield", type: "armor", slot_count: 1, properties: "{}", effects: '{"ac_bonus":2}' },
    { name: "Javelin", type: "weapon", slot_count: 1, properties: "{}", effects: '{"damage":"1d4","melee":true,"stat":"STR","thrown":true,"range":"far"}' },
    { name: "Torch", type: "gear", slot_count: 1, properties: "{}", effects: "{}" },
    { name: "Rations", type: "gear", slot_count: 1, properties: "{}", effects: "{}" },
  ]);
  await addTalents(brynnId, [
    { name: "Weapon Mastery", description: "+1 to attack and damage with longswords", effect: '{"attack_bonus":1,"damage_bonus":1}' },
    { name: "Grit", description: "+2 HP and +1 HP each level", effect: '{"hp_bonus":2,"hp_per_level":1}' },
  ]);

  console.log("Dev data seeded: 2 users, 1 campaign, 2 characters (Limpie & Brynn)");
}
