import 'dotenv/config';
import * as fs from 'fs';
import * as path from 'path';
import { PrismaClient } from '../src/generated/prisma/client.js';
import { PrismaPg } from '@prisma/adapter-pg';

const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
const prisma = new PrismaClient({ adapter });

interface WeaponJson {
  name: string;
  trait: string;
  item_category: string;
  item_subcategory: string;
  bulk: string;
  url: string;
  summary: string;
  hands?: string;
  damage?: string;
  range?: string;
  weapon_category?: string;
}

interface ArmorJson {
  name: string;
  trait: string;
  item_category: string;
  item_subcategory: string;
  bulk: string;
  url: string;
  summary: string;
  ac?: string;
  dex_cap?: string;
}

interface ShieldJson {
  name: string;
  trait: string;
  item_category: string;
  item_subcategory: string;
  bulk: string;
  url: string;
  summary: string;
  ac?: string;
  hp?: string;      // Format: "6 (3)" - HP und Broken Threshold
  hardness?: string;
}

interface EquipmentJson {
  name: string;
  trait: string;
  item_category: string;
  item_subcategory: string;
  bulk: string;
  url: string;
  summary: string;
  activation?: string;
  effect?: string; // Specific effect text for item variants (Lesser, Moderate, Greater, Major)
}

function parseTraits(traitString: string): string[] {
  if (!traitString || traitString.trim() === '') return [];
  return traitString.split(',').map(t => t.trim()).filter(t => t.length > 0);
}

function parseDamage(damageStr: string): { damage: string | null; damageType: string | null } {
  if (!damageStr || damageStr.trim() === '') return { damage: null, damageType: null };

  // Parse strings like "1d8 S", "1d6 P", "2d6 B"
  const match = damageStr.match(/^(.+?)\s+([SPB])$/i);
  if (match) {
    return { damage: match[1].trim(), damageType: match[2].toUpperCase() };
  }
  return { damage: damageStr, damageType: null };
}

function parseNumber(str: string | undefined): number | null {
  if (!str || str.trim() === '') return null;
  const num = parseInt(str, 10);
  return isNaN(num) ? null : num;
}

function parseShieldHp(hpStr: string | undefined): { hp: number | null; bt: number | null } {
  if (!hpStr || hpStr.trim() === '') return { hp: null, bt: null };
  // Format: "6 (3)" oder "12 (6)"
  const match = hpStr.match(/^(\d+)\s*\((\d+)\)$/);
  if (match) {
    return { hp: parseInt(match[1], 10), bt: parseInt(match[2], 10) };
  }
  // Fallback: nur HP
  const num = parseInt(hpStr, 10);
  return { hp: isNaN(num) ? null : num, bt: null };
}

async function seedWeapons() {
  const dataPath = path.join(__dirname, 'data', 'weapons.json');
  const data: WeaponJson[] = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));

  console.log(`⚔️  Importing ${data.length} weapons...`);

  let created = 0;
  let updated = 0;
  let errors = 0;

  for (const item of data) {
    try {
      const { damage, damageType } = parseDamage(item.damage || '');

      // Check if exists first
      const existing = await prisma.equipment.findUnique({ where: { name: item.name } });

      if (existing) {
        // Update with weapon-specific fields
        await prisma.equipment.update({
          where: { name: item.name },
          data: {
            hands: item.hands || existing.hands,
            damage: damage || existing.damage,
            damageType: damageType || existing.damageType,
            range: item.range || existing.range,
            weaponCategory: item.weapon_category || existing.weaponCategory,
            // Don't overwrite traits/summary if already set
            traits: existing.traits.length > 0 ? existing.traits : parseTraits(item.trait),
            summary: existing.summary || item.summary || null,
          },
        });
        updated++;
      } else {
        await prisma.equipment.create({
          data: {
            name: item.name,
            traits: parseTraits(item.trait),
            itemCategory: item.item_category || 'Weapons',
            itemSubcategory: item.item_subcategory || null,
            bulk: item.bulk || null,
            url: item.url || null,
            summary: item.summary || null,
            hands: item.hands || null,
            damage,
            damageType,
            range: item.range || null,
            weaponCategory: item.weapon_category || null,
          },
        });
        created++;
      }
    } catch (error: any) {
      if (errors === 0) {
        // Print full error for first failure only
        console.log(`   ⚠️  First error for "${item.name}":`);
        console.log(error.message);
      }
      errors++;
    }
  }

  console.log(`   ✅ Created: ${created}, Updated: ${updated}, Errors: ${errors}`);
}

async function seedArmor() {
  const dataPath = path.join(__dirname, 'data', 'armor.json');
  const data: ArmorJson[] = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));

  console.log(`🛡️  Importing ${data.length} armor items...`);

  let created = 0;
  let updated = 0;
  let errors = 0;

  for (const item of data) {
    try {
      const existing = await prisma.equipment.findUnique({ where: { name: item.name } });

      if (existing) {
        // Update with armor-specific fields
        await prisma.equipment.update({
          where: { name: item.name },
          data: {
            ac: parseNumber(item.ac) ?? existing.ac,
            dexCap: parseNumber(item.dex_cap) ?? existing.dexCap,
            traits: existing.traits.length > 0 ? existing.traits : parseTraits(item.trait),
            summary: existing.summary || item.summary || null,
          },
        });
        updated++;
      } else {
        await prisma.equipment.create({
          data: {
            name: item.name,
            traits: parseTraits(item.trait),
            itemCategory: item.item_category || 'Armor',
            itemSubcategory: item.item_subcategory || null,
            bulk: item.bulk || null,
            url: item.url || null,
            summary: item.summary || null,
            ac: parseNumber(item.ac),
            dexCap: parseNumber(item.dex_cap),
          },
        });
        created++;
      }
    } catch (error: any) {
      if (errors < 3) {
        console.log(`   ⚠️  Error for "${item.name}": ${error.message?.slice(0, 100)}`);
      }
      errors++;
    }
  }

  console.log(`   ✅ Created: ${created}, Updated: ${updated}, Errors: ${errors}`);
}

async function seedShields() {
  const dataPath = path.join(__dirname, 'data', 'shields.json');
  const data: ShieldJson[] = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));

  console.log(`🛡️  Importing ${data.length} shields...`);

  let created = 0;
  let updated = 0;
  let errors = 0;

  for (const item of data) {
    try {
      const { hp, bt } = parseShieldHp(item.hp);
      const existing = await prisma.equipment.findUnique({ where: { name: item.name } });

      if (existing) {
        await prisma.equipment.update({
          where: { name: item.name },
          data: {
            ac: parseNumber(item.ac) ?? existing.ac,
            shieldHp: hp ?? existing.shieldHp,
            shieldBt: bt ?? existing.shieldBt,
            shieldHardness: parseNumber(item.hardness) ?? existing.shieldHardness,
            traits: existing.traits.length > 0 ? existing.traits : parseTraits(item.trait),
            summary: existing.summary || item.summary || null,
          },
        });
        updated++;
      } else {
        await prisma.equipment.create({
          data: {
            name: item.name,
            traits: parseTraits(item.trait),
            itemCategory: item.item_category || 'Shields',
            itemSubcategory: item.item_subcategory || null,
            bulk: item.bulk || null,
            url: item.url || null,
            summary: item.summary || null,
            ac: parseNumber(item.ac),
            shieldHp: hp,
            shieldBt: bt,
            shieldHardness: parseNumber(item.hardness),
          },
        });
        created++;
      }
    } catch (error: any) {
      if (errors < 3) {
        console.log(`   ⚠️  Error for "${item.name}": ${error.message?.slice(0, 100)}`);
      }
      errors++;
    }
  }

  console.log(`   ✅ Created: ${created}, Updated: ${updated}, Errors: ${errors}`);
}

async function seedEquipment() {
  const dataPath = path.join(__dirname, 'data', 'equipment.json');
  const data: EquipmentJson[] = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));

  console.log(`📦 Importing ${data.length} equipment items...`);

  let created = 0;
  let updated = 0;
  let errors = 0;

  for (const item of data) {
    try {
      await prisma.equipment.upsert({
        where: { name: item.name },
        update: {
          traits: parseTraits(item.trait),
          itemCategory: item.item_category || 'Equipment',
          itemSubcategory: item.item_subcategory || null,
          bulk: item.bulk || null,
          url: item.url || null,
          summary: item.summary || null,
          activation: item.activation || null,
          effect: item.effect || null,
        },
        create: {
          name: item.name,
          traits: parseTraits(item.trait),
          itemCategory: item.item_category || 'Equipment',
          itemSubcategory: item.item_subcategory || null,
          bulk: item.bulk || null,
          url: item.url || null,
          summary: item.summary || null,
          activation: item.activation || null,
          effect: item.effect || null,
        },
      });
      created++;
    } catch (error) {
      // Item with same name already exists - count as update attempt
      updated++;
    }
  }

  console.log(`   ✅ Created: ${created}, Duplicates: ${updated}, Errors: ${errors}`);
}

async function main() {
  console.log('🗃️  Seeding Pathfinder 2e Equipment Database...\n');

  const startTime = Date.now();

  // WICHTIG: Equipment zuerst, dann Waffen/Rüstung/Schilde um spezifische Felder zu ergänzen
  await seedEquipment();
  await seedWeapons();  // Ergänzt damage, hands, weapon_category etc.
  await seedArmor();    // Ergänzt ac, dex_cap etc.
  await seedShields();  // Ergänzt shieldHp, shieldHardness, shieldBt etc.

  const totalCount = await prisma.equipment.count();
  const duration = ((Date.now() - startTime) / 1000).toFixed(1);

  console.log(`\n✅ Equipment database seeded successfully!`);
  console.log(`   Total items in database: ${totalCount}`);
  console.log(`   Duration: ${duration}s`);
}

main()
  .catch((e) => {
    console.error('Equipment seeding failed:', e);
    process.exit(1);
  })
  .finally(() => prisma.$disconnect());
