const express = require('express');
const fs = require('fs');
const path = require('path');
const { bestiaryHelpers, logToFile } = require('../mariadb');
const { requireGM } = require('../auth');
const router = express.Router();

const BESTIARY_FALLBACK_PATH = path.join(__dirname, '..', '..', 'public', 'deathwatch-bestiary-extracted.json');

function loadBestiaryFallback() {
  try {
    const raw = JSON.parse(fs.readFileSync(BESTIARY_FALLBACK_PATH, 'utf8'));
    if (Array.isArray(raw)) return raw;
    if (Array.isArray(raw.results)) return raw.results;
    if (Array.isArray(raw.entries)) return raw.entries;
    if (Array.isArray(raw.items)) return raw.items;
  } catch (error) {
    logToFile('Error loading bestiary fallback:', error);
  }
  return [];
}

// Read bestiary from MariaDB table `bestiary`
async function loadBestiaryData() {
  try {
    const rows = await bestiaryHelpers.getAll();
    if (!rows.length) return loadBestiaryFallback();
    return rows.map(r => {
      let stats = {};
      try { 
        stats = typeof r.stats === 'string' ? JSON.parse(r.stats) : r.stats || {};
      } catch(e){
        logToFile('Error parsing bestiary stats for', r.name, e);
      }
      let profile = {};
      try { 
        profile = typeof r.profile === 'string' ? JSON.parse(r.profile) : r.profile || {};
      } catch(e){
        logToFile('Error parsing bestiary profile for', r.name, e);
      }
      return {
        _id: r.id,
        bestiaryName: r.name,
        book: r.book,
        page: r.page,
        pdf: r.pdf,
        stats: stats,
        profile: profile,
        snippet: r.snippet
      };
    });
  } catch (e) {
    console.error('Failed to load bestiary from MariaDB:', e);
    logToFile('Error loading bestiary:', e);
    return loadBestiaryFallback();
  }
}

// Transform bestiary entry to dice roller format
function transformBestiaryEntry(entry) {
  const stats = entry.stats || {};
  const profile = stats.profile || {};
  const isHorde = !!stats.horde || /horde/i.test(String(entry.bestiaryName || entry.name || ''));
  const magnitudeRaw = stats.magnitude ?? entry.magnitude ?? entry.wounds ?? stats.wounds ?? profile.wounds;

  const parseWeaponDamage = (value) => {
    const text = String(value || '');
    const damage = text.match(/\b\d+d\d+(?:\s*[+-]\s*\d+)?\s*[EIRX]?\b/i);
    const pen = text.match(/\bPen(?:etration)?\s*(\d+)/i);
    return {
      damage: damage ? damage[0].replace(/\s+/g, '') : null,
      pen: pen ? parseInt(pen[1], 10) : null
    };
  };
  
  // Calculate toughness bonus (TB = T/10 rounded down)
  const toughness = profile.t || profile.toughness || 0;
  const tb = Number(stats.toughnessBonus) || Math.floor(toughness / 10);
  
  // Extract armor from various possible locations
  let armour = 0;
  let armourByLoc = null;
  
  if (stats.armour) {
    if (typeof stats.armour === 'number') {
      armour = stats.armour;
    } else if (stats.armour.all !== undefined) {
      armour = Number(stats.armour.all) || 0;
    } else if (stats.armour.body !== undefined) {
      armourByLoc = {
        'Head': stats.armour.head || stats.armour.body || 0,
        'Body': stats.armour.body || 0,
        'Left Arm': stats.armour.leftArm || stats.armour.la || stats.armour.arm || stats.armour.body || 0,
        'Right Arm': stats.armour.rightArm || stats.armour.ra || stats.armour.arm || stats.armour.body || 0,
        'Left Leg': stats.armour.leftLeg || stats.armour.ll || stats.armour.leg || stats.armour.body || 0,
        'Right Leg': stats.armour.rightLeg || stats.armour.rl || stats.armour.leg || stats.armour.body || 0
      };
    }
  }
  
  // Extract wounds, coercing strings like "29" or "29 (X)" to a number and
  // falling back to a usable default so the roller's wounds tracker works.
  const woundsRaw = isHorde ? magnitudeRaw : (entry.wounds ?? stats.wounds ?? profile.wounds);
  let wounds = null;
  if (typeof woundsRaw === 'number' && Number.isFinite(woundsRaw)) {
    wounds = woundsRaw;
  } else if (typeof woundsRaw === 'string') {
    const m = woundsRaw.match(/\d+/);
    if (m) wounds = parseInt(m[0], 10);
  }
  if (!Number.isFinite(wounds) || wounds <= 0) wounds = 15;
  
  // Extract characteristics for defense
  const ag = profile.ag || profile.agility || null;
  const ws = profile.ws || profile.weaponSkill || null;
  const bs = profile.bs || profile.ballisticSkill || null;
  
  const transformed = {
    name: entry.bestiaryName || entry.name || 'Unknown',
    horde: isHorde,
    magnitude: isHorde ? wounds : undefined,
    tb: tb || 4,
    wounds: wounds,
    book: entry.book || '',
    page: entry.page || '',
    // Include characteristics for enemy selection
    ag: ag,
    ws: ws,
    bs: bs
  };

  const weaponDefaults = parseWeaponDamage(stats.weapons || entry.weapons);
  if (weaponDefaults.damage) transformed.damage = weaponDefaults.damage;
  if (weaponDefaults.pen != null) transformed.pen = weaponDefaults.pen;
  
  if (armourByLoc) {
    transformed.armourByLoc = armourByLoc;
  } else {
    transformed.armour = armour;
  }
  
  return transformed;
}

// Get all bestiary entries formatted for dice roller
router.get('/enemies', async (req, res) => {
  try {
    const entries = await loadBestiaryData();
    
    // Transform entries for dice roller format
    // Expose the full bestiary to the roller. transformBestiaryEntry supplies
    // sensible fallbacks (TB, wounds) so entries with sparse stats still work.
    const enemies = entries
      .filter(entry => entry && (entry.bestiaryName || entry.name))
      .map(transformBestiaryEntry);
    
    console.log(`Returning ${enemies.length} enemies for dice roller`);
    res.json(enemies);
  } catch (error) {
    console.error('Bestiary enemies error:', error);
    logToFile('Error getting bestiary enemies:', error);
    res.status(500).json({ error: 'Failed to get enemies' });
  }
});

// Get full bestiary data (for bestiary tab)
router.get('/full', async (req, res) => {
  try {
    const entries = await loadBestiaryData();
    res.json(entries);
  } catch (error) {
    console.error('Bestiary full error:', error);
    logToFile('Error getting full bestiary:', error);
    res.status(500).json({ error: 'Failed to get bestiary data' });
  }
});

// Get bestiary statistics
router.get('/stats', async (req, res) => {
  try {
    const entries = await loadBestiaryData();
    
    const stats = {
      totalEntries: entries.length,
      withValidStats: entries.filter(e => e.stats?.profile?.t).length,
      withWounds: entries.filter(e => e.wounds || e.stats?.wounds).length,
      books: [...new Set(entries.map(e => e.book).filter(Boolean))],
      lastUpdated: new Date().toISOString()
    };
    
    res.json(stats);
  } catch (error) {
    console.error('Bestiary stats error:', error);
    logToFile('Error getting bestiary stats:', error);
    res.status(500).json({ error: 'Failed to get bestiary stats' });
  }
});

// Force reload bestiary data (GM only)
router.post('/reload', async (req, res) => {
  try {
    if (!(await requireGM(req, res))) return;
    
    // No cache to reset since we query MariaDB directly
    const entries = await loadBestiaryData();
    res.json({
      success: true,
      totalEntries: entries.length,
      message: 'Bestiary data reloaded from MariaDB successfully'
    });
    
  } catch (error) {
    console.error('Bestiary reload error:', error);
    logToFile('Error reloading bestiary:', error);
    res.status(500).json({ error: 'Failed to reload bestiary data' });
  }
});

console.log('Bestiary routes registered');
module.exports = router;
