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 RawFeat {
  name: string;
  trait: string;
  summary: string;
  actions: string;
  damage: string;
  trigger: string;
  url: string;
}

interface FeatLevelData {
  name: string;
  level: string;
  prerequisite: string;
}

// Known classes in Pathfinder 2e
const CLASSES = [
  'Alchemist', 'Barbarian', 'Bard', 'Champion', 'Cleric', 'Druid',
  'Fighter', 'Gunslinger', 'Inventor', 'Investigator', 'Kineticist',
  'Magus', 'Monk', 'Oracle', 'Psychic', 'Ranger', 'Rogue', 'Sorcerer',
  'Summoner', 'Swashbuckler', 'Thaumaturge', 'Witch', 'Wizard',
  // Archetype dedication markers
  'Archetype',
];

// Known ancestries in Pathfinder 2e
const ANCESTRIES = [
  'Android', 'Anadi', 'Aasimar', 'Aphorite', 'Automaton', 'Azarketi',
  'Beastkin', 'Catfolk', 'Changeling', 'Conrasu', 'Dhampir', 'Duskwalker',
  'Dwarf', 'Elf', 'Fetchling', 'Fleshwarp', 'Ganzi', 'Ghoran', 'Gnoll',
  'Gnome', 'Goblin', 'Goloma', 'Grippli', 'Halfling', 'Hobgoblin', 'Human',
  'Ifrit', 'Kashrishi', 'Kitsune', 'Kobold', 'Leshy', 'Lizardfolk', 'Nagaji',
  'Orc', 'Oread', 'Poppet', 'Ratfolk', 'Reflection', 'Shisk', 'Shoony',
  'Skeleton', 'Sprite', 'Strix', 'Suli', 'Sylph', 'Tanuki', 'Tengu',
  'Tiefling', 'Undine', 'Vanara', 'Vishkanya', 'Wayang',
  // Heritage markers
  'Half-Elf', 'Half-Orc', 'Versatile Heritage',
];

// Rarity levels
const RARITIES = ['Common', 'Uncommon', 'Rare', 'Unique'];

// Feat type markers
const GENERAL_MARKERS = ['General'];
const SKILL_MARKERS = ['Skill'];

// Clean up prerequisites text
function cleanPrerequisites(prereq: string): string | null {
  if (!prereq || prereq.trim() === '') return null;

  let cleaned = prereq.trim();

  // Remove leading semicolons or commas
  cleaned = cleaned.replace(/^[;,\s]+/, '');

  // Normalize some common patterns
  cleaned = cleaned.replace(/\s+/g, ' '); // normalize whitespace

  return cleaned || null;
}

function parseFeat(raw: RawFeat, levelData?: FeatLevelData) {
  const traits = raw.trait.split(',').map(t => t.trim()).filter(Boolean);

  let featType: string | null = null;
  let className: string | null = null;
  let ancestryName: string | null = null;
  let archetypeName: string | null = null;
  let skillName: string | null = null;
  let rarity: string = 'Common';
  const actualTraits: string[] = [];

  for (const trait of traits) {
    // Check for rarity
    if (RARITIES.includes(trait)) {
      rarity = trait;
      continue;
    }

    // Check for class
    if (CLASSES.includes(trait)) {
      if (trait === 'Archetype') {
        featType = 'Archetype';
      } else {
        className = trait;
        featType = 'Class';
      }
      continue;
    }

    // Check for ancestry
    if (ANCESTRIES.includes(trait)) {
      ancestryName = trait;
      featType = 'Ancestry';
      continue;
    }

    // Check for general/skill markers
    if (GENERAL_MARKERS.includes(trait)) {
      if (!featType) featType = 'General';
      continue;
    }

    if (SKILL_MARKERS.includes(trait)) {
      featType = 'Skill';
      continue;
    }

    // Check for lineage/heritage
    if (trait === 'Lineage' || trait === 'Heritage') {
      featType = 'Heritage';
      continue;
    }

    // Everything else is an actual trait
    actualTraits.push(trait);
  }

  // Parse actions
  let actions: string | null = null;
  if (raw.actions) {
    const actionsLower = raw.actions.toLowerCase();
    if (actionsLower.includes('free')) {
      actions = 'free';
    } else if (actionsLower.includes('reaction')) {
      actions = 'reaction';
    } else if (actionsLower.includes('1') || actionsLower === 'a') {
      actions = '1';
    } else if (actionsLower.includes('2') || actionsLower === 'aa') {
      actions = '2';
    } else if (actionsLower.includes('3') || actionsLower === 'aaa') {
      actions = '3';
    }
  }

  // Get level and prerequisites from levelData if available
  const level = levelData ? parseInt(levelData.level, 10) : null;
  const prerequisites = levelData ? cleanPrerequisites(levelData.prerequisite) : null;

  return {
    name: raw.name,
    traits: actualTraits,
    summary: raw.summary || null,
    description: raw.trigger ? `Trigger: ${raw.trigger}` : null,
    actions,
    url: raw.url || null,
    featType,
    rarity,
    className,
    ancestryName,
    archetypeName,
    skillName,
    level,
    prerequisites,
  };
}

async function seedFeats() {
  console.log('Starting feats seed...');

  // Read feats JSON
  const featsPath = path.join(__dirname, 'data', 'feats.json');
  const rawFeats: RawFeat[] = JSON.parse(fs.readFileSync(featsPath, 'utf-8'));
  console.log(`Found ${rawFeats.length} feats to import`);

  // Read feat levels JSON
  const levelsPath = path.join(__dirname, 'data', 'featlevels.json');
  let levelDataMap = new Map<string, FeatLevelData>();

  if (fs.existsSync(levelsPath)) {
    const levelData: FeatLevelData[] = JSON.parse(fs.readFileSync(levelsPath, 'utf-8'));
    console.log(`Found ${levelData.length} feat level entries`);

    // Create lookup map by name (case-insensitive)
    levelData.forEach(ld => {
      levelDataMap.set(ld.name.toLowerCase(), ld);
    });
  } else {
    console.log('Warning: featlevels.json not found, skipping level data');
  }

  // Clear existing feats
  console.log('Clearing existing feats...');
  await prisma.feat.deleteMany();

  // Parse and prepare feats with level data
  let matchedCount = 0;
  const feats = rawFeats.map(raw => {
    const levelData = levelDataMap.get(raw.name.toLowerCase());
    if (levelData) matchedCount++;
    return parseFeat(raw, levelData);
  });

  console.log(`Matched ${matchedCount}/${rawFeats.length} feats with level data`);

  // Insert in batches to avoid memory issues
  const BATCH_SIZE = 500;
  let inserted = 0;

  for (let i = 0; i < feats.length; i += BATCH_SIZE) {
    const batch = feats.slice(i, i + BATCH_SIZE);

    // Use createMany with skipDuplicates for efficiency
    try {
      await prisma.feat.createMany({
        data: batch,
        skipDuplicates: true,
      });
      inserted += batch.length;
      console.log(`Inserted ${inserted}/${feats.length} feats...`);
    } catch (error) {
      // If batch fails, try one by one to identify problematic entries
      console.log(`Batch failed, inserting one by one...`);
      for (const feat of batch) {
        try {
          await prisma.feat.create({ data: feat });
          inserted++;
        } catch (e) {
          console.warn(`Failed to insert feat: ${feat.name}`, e);
        }
      }
    }
  }

  // Count results
  const totalFeats = await prisma.feat.count();
  const classFeatCount = await prisma.feat.count({ where: { featType: 'Class' } });
  const ancestryFeatCount = await prisma.feat.count({ where: { featType: 'Ancestry' } });
  const generalFeatCount = await prisma.feat.count({ where: { featType: 'General' } });
  const skillFeatCount = await prisma.feat.count({ where: { featType: 'Skill' } });
  const archetypeFeatCount = await prisma.feat.count({ where: { featType: 'Archetype' } });
  const withLevel = await prisma.feat.count({ where: { level: { not: null } } });
  const withPrereqs = await prisma.feat.count({ where: { prerequisites: { not: null } } });

  console.log('\n=== Feats Import Complete ===');
  console.log(`Total feats: ${totalFeats}`);
  console.log(`Class feats: ${classFeatCount}`);
  console.log(`Ancestry feats: ${ancestryFeatCount}`);
  console.log(`General feats: ${generalFeatCount}`);
  console.log(`Skill feats: ${skillFeatCount}`);
  console.log(`Archetype feats: ${archetypeFeatCount}`);
  console.log(`Feats with level: ${withLevel}`);
  console.log(`Feats with prerequisites: ${withPrereqs}`);
}

seedFeats()
  .catch((e) => {
    console.error('Error seeding feats:', e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
