const db = require('../db/db');
const { awardXP, checkRedBookAchievements } = require('./gamificationController');
const { stripTags } = require('../utils/sanitize');

/* ── helpers ─────────────────────────────────────────────────────────── */
const stmts = {
  groups:      db.prepare('SELECT * FROM rb_groups ORDER BY name_ru'),
  habitats:    db.prepare('SELECT * FROM rb_habitats ORDER BY name'),
  speciesById: db.prepare(`
    SELECT s.*, g.name_ru as group_name, g.icon as group_icon, g.color as group_color,
           h.name as habitat_name, h.type as habitat_type
    FROM rb_species s
    JOIN rb_groups g ON g.id = s.group_id
    LEFT JOIN rb_habitats h ON h.id = s.habitat_id
    WHERE s.id = ?
  `),
  regionsBySpecies: db.prepare('SELECT region_code FROM rb_species_regions WHERE species_id = ?'),
  popdata:     db.prepare('SELECT year, count_estimate, source FROM rb_population_data WHERE species_id = ? ORDER BY year'),
  foodWebPrey: db.prepare(`
    SELECT fw.strength, s.id, s.name_ru, s.name_lat, s.category,
           g.icon as group_icon, g.color as group_color
    FROM rb_food_web fw
    JOIN rb_species s ON s.id = fw.prey_id
    JOIN rb_groups g ON g.id = s.group_id
    WHERE fw.predator_id = ?
  `),
  foodWebPredators: db.prepare(`
    SELECT fw.strength, s.id, s.name_ru, s.name_lat, s.category,
           g.icon as group_icon, g.color as group_color
    FROM rb_food_web fw
    JOIN rb_species s ON s.id = fw.predator_id
    JOIN rb_groups g ON g.id = s.group_id
    WHERE fw.prey_id = ?
  `),
  collection:  db.prepare('SELECT species_id, unlock_method, notes, unlocked_at FROM rb_user_collection WHERE user_id = ?'),
  hasCollect:  db.prepare('SELECT 1 FROM rb_user_collection WHERE user_id = ? AND species_id = ?'),
  addCollect:  db.prepare('INSERT OR IGNORE INTO rb_user_collection (user_id, species_id, unlock_method) VALUES (?,?,?)'),
  quests:      db.prepare('SELECT * FROM rb_quests ORDER BY id'),
  userQuests:  db.prepare('SELECT * FROM rb_user_quests WHERE user_id = ?'),
  startQuest:  db.prepare('INSERT OR IGNORE INTO rb_user_quests (user_id, quest_id) VALUES (?,?)'),
  questById:   db.prepare('SELECT * FROM rb_quests WHERE id = ?'),
  userQuestRow:db.prepare('SELECT * FROM rb_user_quests WHERE user_id = ? AND quest_id = ?'),
  completeQ:   db.prepare("UPDATE rb_user_quests SET status='completed', completed_at=datetime('now') WHERE user_id=? AND quest_id=?"),
  sightings:   db.prepare(`
    SELECT rs.*, u.name as user_name, s.name_ru as species_name
    FROM rb_sightings rs
    JOIN users u ON u.id = rs.user_id
    JOIN rb_species s ON s.id = rs.species_id
    ORDER BY rs.created_at DESC LIMIT 50
  `),
  addSighting: db.prepare('INSERT INTO rb_sightings (user_id, species_id, region_code, description) VALUES (?,?,?,?)'),
  mapData:     db.prepare(`
    SELECT r.region_code, COUNT(r.species_id) as total,
           SUM(CASE WHEN s.category='CR' THEN 1 ELSE 0 END) as cr,
           SUM(CASE WHEN s.category='EN' THEN 1 ELSE 0 END) as en,
           SUM(CASE WHEN s.category='VU' THEN 1 ELSE 0 END) as vu
    FROM rb_species_regions r
    JOIN rb_species s ON s.id = r.species_id
    GROUP BY r.region_code
  `),
};

function buildSpeciesList(filter = {}) {
  let sql = `
    SELECT s.id, s.name_ru, s.name_be, s.name_lat, s.category, s.by_category,
           s.photo_url, s.model_type, s.biomass_kg, s.interesting_fact,
           g.name_ru as group_name, g.icon as group_icon, g.color as group_color,
           h.name as habitat_name, h.type as habitat_type
    FROM rb_species s
    JOIN rb_groups g ON g.id = s.group_id
    LEFT JOIN rb_habitats h ON h.id = s.habitat_id
  `;
  const cond = [], params = [];
  if (filter.group_id) { cond.push('s.group_id = ?'); params.push(filter.group_id); }
  if (filter.category) { cond.push('s.category = ?'); params.push(filter.category); }
  if (filter.habitat_id) { cond.push('s.habitat_id = ?'); params.push(filter.habitat_id); }
  if (filter.region) {
    sql += ' JOIN rb_species_regions rr ON rr.species_id = s.id';
    cond.push('rr.region_code = ?'); params.push(filter.region);
  }
  if (filter.q) {
    cond.push('(s.name_ru LIKE ? OR s.name_lat LIKE ? OR s.name_be LIKE ?)');
    const like = `%${filter.q}%`;
    params.push(like, like, like);
  }
  if (cond.length) sql += ' WHERE ' + cond.join(' AND ');
  sql += ' ORDER BY s.category, s.name_ru';
  const limit = Math.min(parseInt(filter.limit) || 50, 100);
  const offset = parseInt(filter.offset) || 0;
  sql += ' LIMIT ? OFFSET ?';
  params.push(limit, offset);
  return db.prepare(sql).all(...params);
}

/* ── GET /api/red-book/groups ───────────────────────────────────────── */
exports.getGroups = (req, res) => {
  const groups = stmts.groups.all();
  // attach count
  const counts = db.prepare(`
    SELECT group_id, COUNT(*) as n,
           SUM(CASE WHEN category='CR' THEN 1 ELSE 0 END) as cr,
           SUM(CASE WHEN category='EN' THEN 1 ELSE 0 END) as en
    FROM rb_species GROUP BY group_id
  `).all();
  const countMap = {};
  counts.forEach(c => countMap[c.group_id] = { n: c.n, cr: c.cr, en: c.en });
  groups.forEach(g => Object.assign(g, countMap[g.id] || { n: 0, cr: 0, en: 0 }));
  res.json(groups);
};

/* ── GET /api/red-book/habitats ─────────────────────────────────────── */
exports.getHabitats = (req, res) => {
  res.json(stmts.habitats.all());
};

/* ── GET /api/red-book/species ──────────────────────────────────────── */
exports.getSpecies = (req, res) => {
  const list = buildSpeciesList(req.query);
  // total for pagination
  const total = db.prepare('SELECT COUNT(*) as n FROM rb_species').get().n;
  // user collection ids
  let collected = new Set();
  if (req.user) {
    stmts.collection.all(req.user.id).forEach(r => collected.add(r.species_id));
  }
  list.forEach(s => {
    try { s.threats = JSON.parse(s.threats || '[]'); } catch { s.threats = []; }
    s.collected = collected.has(s.id);
  });
  res.json({ total, species: list });
};

/* ── GET /api/red-book/species/:id ─────────────────────────────────── */
exports.getSpeciesById = (req, res) => {
  const s = stmts.speciesById.get(req.params.id);
  if (!s) return res.status(404).json({ error: 'Вид не найден' });
  s.regions     = stmts.regionsBySpecies.all(s.id).map(r => r.region_code);
  s.population_data = stmts.popdata.all(s.id);
  s.prey        = stmts.foodWebPrey.all(s.id);
  s.predators   = stmts.foodWebPredators.all(s.id);
  try { s.threats = JSON.parse(s.threats || '[]'); } catch { s.threats = []; }
  try { s.population_trend = JSON.parse(s.population_trend || '[]'); } catch { s.population_trend = []; }
  if (req.user) {
    s.collected = !!stmts.hasCollect.get(req.user.id, s.id);
  }
  res.json(s);
};

/* ── GET /api/red-book/map-data ─────────────────────────────────────── */
exports.getMapData = (req, res) => {
  res.json(stmts.mapData.all());
};

/* ── GET /api/red-book/food-web ─────────────────────────────────────── */
exports.getFoodWeb = (req, res) => {
  const ids = (req.query.species_ids || '').split(',').map(Number).filter(Boolean);
  if (!ids.length) {
    // return full web
    const nodes = db.prepare(`
      SELECT s.id, s.name_ru, s.name_lat, s.category, s.biomass_kg, s.description,
             g.icon, g.color, g.id as group_id,
             h.id as habitat_id, h.type as habitat_type, h.name as habitat_name
      FROM rb_species s
      JOIN rb_groups g ON g.id = s.group_id
      LEFT JOIN rb_habitats h ON h.id = s.habitat_id
    `).all();
    const links = db.prepare('SELECT predator_id as source, prey_id as target, strength FROM rb_food_web').all();
    return res.json({ nodes, links });
  }
  const ph = ids.map(() => '?').join(',');
  const nodes = db.prepare(`
    SELECT s.id, s.name_ru, s.name_lat, s.category, s.biomass_kg, s.description, g.icon, g.color
    FROM rb_species s JOIN rb_groups g ON g.id = s.group_id
    WHERE s.id IN (${ph})
  `).all(...ids);
  const links = db.prepare(`
    SELECT predator_id as source, prey_id as target, strength FROM rb_food_web
    WHERE predator_id IN (${ph}) OR prey_id IN (${ph})
  `).all(...ids, ...ids);
  res.json({ nodes, links });
};

/* ── GET /api/red-book/biome/:habitatId ─────────────────────────────── */
exports.getBiomeSpecies = (req, res) => {
  const list = db.prepare(`
    SELECT s.id, s.name_ru, s.name_lat, s.category, s.photo_url, s.model_type,
           s.biomass_kg, g.icon, g.color
    FROM rb_species s JOIN rb_groups g ON g.id = s.group_id
    WHERE s.habitat_id = ?
    ORDER BY s.category, s.name_ru
  `).all(req.params.habitatId);
  res.json(list);
};

/* ── POST /api/red-book/species/:id/collect ─────────────────────────── */
exports.collectSpecies = (req, res) => {
  const userId = req.user.id;
  const speciesId = parseInt(req.params.id);
  const sp = stmts.speciesById.get(speciesId);
  if (!sp) return res.status(404).json({ error: 'Вид не найден' });

  const already = stmts.hasCollect.get(userId, speciesId);
  if (already) return res.json({ already: true, message: 'Вид уже в коллекции' });

  stmts.addCollect.run(userId, speciesId, req.body?.method || 'explore');

  // Award XP (via gamification service — also updates level in DB)
  const xpMap = { CR: 50, EN: 40, VU: 30, NT: 20, LC: 10 };
  const xp = xpMap[sp.category] || 20;
  try { awardXP(userId, xp, `Открыт вид: ${sp.name_ru}`); } catch {}

  // Auto-complete any active quests that required this species
  const completedQuests = [];
  try {
    const activeQuests = db.prepare(`
      SELECT q.*, uq.quest_id FROM rb_user_quests uq
      JOIN rb_quests q ON q.id = uq.quest_id
      WHERE uq.user_id = ? AND uq.status = 'active'
    `).all(userId);

    // Get all collected species ids for this user
    const collectedIds = new Set(
      db.prepare('SELECT species_id FROM rb_user_collection WHERE user_id = ?').all(userId).map(r => r.species_id)
    );

    for (const quest of activeQuests) {
      const requiredIds = JSON.parse(quest.species_ids || '[]');
      if (requiredIds.every(id => collectedIds.has(id))) {
        stmts.completeQ.run(userId, quest.id);
        // Award quest XP via gamification service
        try { awardXP(userId, quest.xp_reward, `Квест выполнен: ${quest.title}`); } catch {}
        completedQuests.push({ id: quest.id, title: quest.title, xp_reward: quest.xp_reward });
      }
    }
  } catch {}

  // Check Red Book achievements (non-blocking)
  try { checkRedBookAchievements(userId); } catch {}

  res.json({ collected: true, xp_earned: xp, species: { id: sp.id, name_ru: sp.name_ru, category: sp.category }, completed_quests: completedQuests });
};

/* ── GET /api/red-book/collection ───────────────────────────────────── */
exports.getCollection = (req, res) => {
  const rows = stmts.collection.all(req.user.id);
  const ids = rows.map(r => r.species_id);
  if (!ids.length) return res.json({ total: 0, species: [] });
  const ph = ids.map(() => '?').join(',');
  const species = db.prepare(`
    SELECT s.id, s.name_ru, s.name_lat, s.category, s.photo_url,
           g.icon, g.color
    FROM rb_species s JOIN rb_groups g ON g.id = s.group_id
    WHERE s.id IN (${ph})
  `).all(...ids);
  const meta = {};
  rows.forEach(r => meta[r.species_id] = { method: r.unlock_method, notes: r.notes, at: r.unlocked_at });
  species.forEach(s => Object.assign(s, meta[s.id] || {}));
  res.json({ total: species.length, species });
};

/* ── GET /api/red-book/quests ───────────────────────────────────────── */
exports.getQuests = (req, res) => {
  const quests = stmts.quests.all();
  quests.forEach(q => q.species_ids = JSON.parse(q.species_ids || '[]'));
  if (!req.user) return res.json(quests);
  const userQ = {};
  stmts.userQuests.all(req.user.id).forEach(uq => userQ[uq.quest_id] = uq);
  quests.forEach(q => {
    const uq = userQ[q.id];
    q.user_status   = uq?.status || 'locked';
    q.user_progress = uq ? JSON.parse(uq.progress || '{}') : {};
  });
  res.json(quests);
};

/* ── POST /api/red-book/quests/:id/start ────────────────────────────── */
exports.startQuest = (req, res) => {
  const q = stmts.questById.get(req.params.id);
  if (!q) return res.status(404).json({ error: 'Квест не найден' });
  stmts.startQuest.run(req.user.id, q.id);
  res.json({ started: true });
};

/* ── GET /api/red-book/sightings ────────────────────────────────────── */
exports.getSightings = (req, res) => {
  const speciesId = req.query.species_id ? parseInt(req.query.species_id) : null;
  let sql = `
    SELECT rs.id, rs.species_id, rs.region_code, rs.description,
           rs.confirmed_by_teacher, rs.created_at,
           u.name as user_name,
           s.name_ru as species_name,
           g.icon as species_icon
    FROM rb_sightings rs
    JOIN users u ON u.id = rs.user_id
    JOIN rb_species s ON s.id = rs.species_id
    JOIN rb_groups g ON g.id = s.group_id
  `;
  const params = [];
  if (speciesId) { sql += ' WHERE rs.species_id = ?'; params.push(speciesId); }
  sql += ' ORDER BY rs.created_at DESC LIMIT 50';
  res.json(db.prepare(sql).all(...params));
};

/* ── POST /api/red-book/sightings ───────────────────────────────────── */
exports.addSighting = (req, res) => {
  const { species_id, region_code, description } = req.body || {};
  if (!species_id) return res.status(400).json({ error: 'species_id обязателен' });
  const safeDesc = stripTags((description || '').slice(0, 2000));
  const id = stmts.addSighting.run(req.user.id, species_id, region_code || '', safeDesc).lastInsertRowid;
  try { checkRedBookAchievements(req.user.id); } catch {}
  res.json({ id });
};

/* ── GET /api/red-book/stats ────────────────────────────────────────── */
exports.getStats = (req, res) => {
  const totals = db.prepare(`
    SELECT COUNT(*) as total,
           SUM(CASE WHEN category='CR' THEN 1 ELSE 0 END) as cr,
           SUM(CASE WHEN category='EN' THEN 1 ELSE 0 END) as en,
           SUM(CASE WHEN category='VU' THEN 1 ELSE 0 END) as vu,
           SUM(CASE WHEN category='NT' THEN 1 ELSE 0 END) as nt,
           SUM(CASE WHEN category='LC' THEN 1 ELSE 0 END) as lc
    FROM rb_species
  `).get();
  let collected = 0;
  if (req.user) {
    collected = db.prepare('SELECT COUNT(*) as n FROM rb_user_collection WHERE user_id = ?').get(req.user.id).n;
  }
  res.json({ ...totals, collected });
};

/* ── GET /api/red-book/daily ────────────────────────────────────────── */
exports.getDaily = (req, res) => {
  // deterministic by day of year
  const dayOfYear = Math.floor((Date.now() - new Date(new Date().getFullYear(), 0, 0)) / 86400000);
  const total = db.prepare('SELECT COUNT(*) as n FROM rb_species').get().n;
  const offset = dayOfYear % total;
  const daily = db.prepare(`
    SELECT s.id, s.name_ru, s.name_lat, s.category, s.interesting_fact,
           s.description, s.photo_url, g.icon, g.color
    FROM rb_species s JOIN rb_groups g ON g.id = s.group_id
    ORDER BY s.id LIMIT 1 OFFSET ?
  `).get(offset);
  res.json(daily);
};
