import { Router, Response } from 'express';
import { z } from 'zod';
import { queryOne, queryMany, exec, withTransaction } from '../db/pool';
import { authenticate, AuthenticatedRequest } from '../middleware/auth';
import { logger } from '../lib/logger';
import { breedGenotypes, genotypeToPhenotype, computeRarity, generateBreedPreview, computeInbreedingCoefficient, type Genotype } from '../lib/genetics';
import { v4 as uuidv4 } from 'uuid';

const router = Router();
router.use(authenticate);

const BREEDING_COST = 30;
const PREGNANCY_HOURS = 72;

async function loadGenotype(animalId: string): Promise<Genotype | null> {
  const row = await queryOne<any>('SELECT * FROM animal_genotypes WHERE animal_id = ?', [animalId]);
  if (!row) return null;
  return {
    gWeight: parseFloat(row.g_weight), gMilkYield: parseFloat(row.g_milk_yield),
    gGrowthRate: parseFloat(row.g_growth_rate), gTemperament: parseFloat(row.g_temperament),
    gCoatQuality: parseFloat(row.g_coat_quality), gFertility: parseFloat(row.g_fertility),
    gHardiness: parseFloat(row.g_hardiness), gShowPotential: parseFloat(row.g_show_potential),
  };
}

async function getAncestors(animalId: string): Promise<Map<string, number>> {
  const rows = await queryMany<any>('SELECT ancestor_id, generation FROM lineage WHERE animal_id = ?', [animalId]);
  return new Map(rows.map(r => [r.ancestor_id, parseInt(r.generation)]));
}

// ─── POST /breed/preview ──────────────────────────────────────────────────────

router.post('/preview', async (req: AuthenticatedRequest, res: Response) => {
  const parsed = z.object({ sireId: z.string().uuid(), damId: z.string().uuid() }).safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'VALIDATION_ERROR' });

  const { sireId, damId } = parsed.data;
  const userId = req.user!.id;

  try {
    const sire = await queryOne<any>('SELECT id, sex, stage, status, owner_id FROM animals WHERE id = ? AND died_at IS NULL', [sireId]);
    const dam  = await queryOne<any>('SELECT id, sex, stage, status, owner_id FROM animals WHERE id = ? AND died_at IS NULL', [damId]);

    if (!sire || !dam) return res.status(404).json({ error: 'NOT_FOUND' });
    if (sire.owner_id !== userId || dam.owner_id !== userId) return res.status(403).json({ error: 'FORBIDDEN' });
    if (sire.sex !== 'male') return res.status(400).json({ error: 'INVALID_PAIR', message: 'Sire must be male' });
    if (dam.sex !== 'female') return res.status(400).json({ error: 'INVALID_PAIR', message: 'Dam must be female' });

    const [sg, dg] = await Promise.all([loadGenotype(sireId), loadGenotype(damId)]);
    if (!sg || !dg) return res.status(500).json({ error: 'INTERNAL_ERROR' });

    const [sireAncs, damAncs] = await Promise.all([getAncestors(sireId), getAncestors(damId)]);
    const inbreedingCoeff = computeInbreedingCoefficient(sireAncs, damAncs);
    const preview = generateBreedPreview(sg, dg, inbreedingCoeff, 3000);

    res.json({ sireId, damId, ...preview, inbreedingCoefficient: inbreedingCoeff, inbreedingWarning: inbreedingCoeff > 0.25, cost: BREEDING_COST });
  } catch (err) {
    logger.error('Breed preview error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

// ─── POST /breed ──────────────────────────────────────────────────────────────

router.post('/', async (req: AuthenticatedRequest, res: Response) => {
  const parsed = z.object({ sireId: z.string().uuid(), damId: z.string().uuid() }).safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'VALIDATION_ERROR' });

  const { sireId, damId } = parsed.data;
  const userId = req.user!.id;

  try {
    await withTransaction(async (client) => {
      // Lock rows
      const [[sireRows], [damRows]] = await Promise.all([
        client.execute('SELECT * FROM animals WHERE id = ? AND died_at IS NULL FOR UPDATE', [sireId]),
        client.execute('SELECT * FROM animals WHERE id = ? AND died_at IS NULL FOR UPDATE', [damId]),
      ]) as any[];

      const s = (sireRows as any[])[0];
      const d = (damRows  as any[])[0];

      if (!s || !d) throw { statusCode: 404, error: 'NOT_FOUND' };
      if (s.owner_id !== userId || d.owner_id !== userId) throw { statusCode: 403, error: 'FORBIDDEN' };
      if (s.sex !== 'male')   throw { statusCode: 400, error: 'INVALID', message: 'Sire must be male' };
      if (d.sex !== 'female') throw { statusCode: 400, error: 'INVALID', message: 'Dam must be female' };
      if (!['adult','elder'].includes(s.stage)) throw { statusCode: 400, error: 'NOT_ADULT', message: 'Sire must be an adult' };
      if (!['adult','elder'].includes(d.stage)) throw { statusCode: 400, error: 'NOT_ADULT', message: 'Dam must be an adult' };
      if (d.status === 'pregnant')   throw { statusCode: 400, error: 'ALREADY_PREGNANT', message: 'Dam is already pregnant' };
      if (d.status === 'recovering') throw { statusCode: 400, error: 'RECOVERING', message: 'Dam is still recovering' };
      if (parseFloat(d.health) < 30) throw { statusCode: 400, error: 'TOO_SICK', message: 'Dam is too sick to breed' };

      // Deduct gold
      const [deduct] = await client.execute(
        'UPDATE users SET gold_balance = gold_balance - ? WHERE id = ? AND gold_balance >= ?',
        [BREEDING_COST, userId, BREEDING_COST]
      ) as any[];

      if ((deduct as any).affectedRows === 0) throw { statusCode: 400, error: 'INSUFFICIENT_GOLD', message: `Breeding costs ${BREEDING_COST} Gold` };

      // Compute offspring
      const [sgRows] = await client.execute('SELECT * FROM animal_genotypes WHERE animal_id = ?', [sireId]) as any[];
      const [dgRows] = await client.execute('SELECT * FROM animal_genotypes WHERE animal_id = ?', [damId]) as any[];

      const sg = (sgRows as any[])[0];
      const dg = (dgRows as any[])[0];

      if (!sg || !dg) throw { statusCode: 500, error: 'GENOTYPE_MISSING', message: 'Missing genotype data for sire or dam' };

      const sireGeno: Genotype = { gWeight: parseFloat(sg.g_weight), gMilkYield: parseFloat(sg.g_milk_yield), gGrowthRate: parseFloat(sg.g_growth_rate), gTemperament: parseFloat(sg.g_temperament), gCoatQuality: parseFloat(sg.g_coat_quality), gFertility: parseFloat(sg.g_fertility), gHardiness: parseFloat(sg.g_hardiness), gShowPotential: parseFloat(sg.g_show_potential) };
      const damGeno:  Genotype = { gWeight: parseFloat(dg.g_weight), gMilkYield: parseFloat(dg.g_milk_yield), gGrowthRate: parseFloat(dg.g_growth_rate), gTemperament: parseFloat(dg.g_temperament), gCoatQuality: parseFloat(dg.g_coat_quality), gFertility: parseFloat(dg.g_fertility), gHardiness: parseFloat(dg.g_hardiness), gShowPotential: parseFloat(dg.g_show_potential) };

      const sireAncs = await getAncestors(sireId);
      const damAncs  = await getAncestors(damId);
      const inbreedingCoeff = computeInbreedingCoefficient(sireAncs, damAncs);

      const offspringGenotype = breedGenotypes(sireGeno, damGeno, inbreedingCoeff);
      const offspringPhenotype = genotypeToPhenotype(offspringGenotype);
      const offspringRarity = computeRarity(offspringGenotype);

      const offspringId = uuidv4();
      const pregnancyEnd = new Date(Date.now() + PREGNANCY_HOURS * 60 * 60 * 1000);
      const offspringSex = Math.random() < 0.5 ? 'male' : 'female';

      const [[ranchRows]] = await client.execute('SELECT id FROM ranches WHERE owner_id = ?', [userId]) as any[];
      const ranchId = ((ranchRows as any[])[0]).id;

      await client.execute(
        `INSERT INTO animals (id, owner_id, ranch_id, name, breed, sex, stage, status, sire_id, dam_id, inbreeding_coefficient, rarity_tier)
         VALUES (?, ?, ?, 'Unborn Calf', ?, ?, 'calf', 'recovering', ?, ?, ?, ?)`,
        [offspringId, userId, ranchId, d.breed, offspringSex, sireId, damId, inbreedingCoeff, offspringRarity]
      );

      await client.execute(
        `INSERT INTO animal_phenotypes (animal_id, weight_score, milk_yield_score, growth_rate_score, temperament_score, coat_quality_score, fertility_score, hardiness_score, show_potential_score)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [offspringId, offspringPhenotype.weightScore, offspringPhenotype.milkYieldScore, offspringPhenotype.growthRateScore, offspringPhenotype.temperamentScore, offspringPhenotype.coatQualityScore, offspringPhenotype.fertilityScore, offspringPhenotype.hardinessScore, offspringPhenotype.showPotentialScore]
      );

      await client.execute(
        `INSERT INTO animal_genotypes (animal_id, g_weight, g_milk_yield, g_growth_rate, g_temperament, g_coat_quality, g_fertility, g_hardiness, g_show_potential)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [offspringId, offspringGenotype.gWeight, offspringGenotype.gMilkYield, offspringGenotype.gGrowthRate, offspringGenotype.gTemperament, offspringGenotype.gCoatQuality, offspringGenotype.gFertility, offspringGenotype.gHardiness, offspringGenotype.gShowPotential]
      );

      await client.execute(
        `UPDATE animals SET status = 'pregnant', pregnancy_end_at = ?, updated_at = NOW() WHERE id = ?`,
        [pregnancyEnd, damId]
      );

      // Lineage
      await client.execute(
        `INSERT INTO lineage (id, animal_id, ancestor_id, generation) VALUES (?, ?, ?, 1), (?, ?, ?, 1)`,
        [uuidv4(), offspringId, sireId, uuidv4(), offspringId, damId]
      );

      for (const [parentAncs, _] of [[sireAncs, sireId], [damAncs, damId]]) {
        for (const [ancId, gen] of (parentAncs as Map<string, number>)) {
          if (gen < 5) {
            await client.execute(
              `INSERT IGNORE INTO lineage (id, animal_id, ancestor_id, generation) VALUES (?, ?, ?, ?)`,
              [uuidv4(), offspringId, ancId, gen + 1]
            );
          }
        }
      }

      const [[userRow]] = await client.execute('SELECT gold_balance FROM users WHERE id = ?', [userId]) as any[];
      await client.execute(
        `INSERT INTO transactions (id, user_id, amount, currency, category, balance_after, description)
         VALUES (?, ?, ?, 'gold', 'fee', ?, ?)`,
        [uuidv4(), userId, -BREEDING_COST, (userRow as any[])[0].gold_balance, `Breeding: ${s.name} × ${d.name}`]
      );

      res.status(201).json({
        success: true,
        message: `${d.name} is now pregnant! Birth expected in ${PREGNANCY_HOURS} hours.`,
        pregnancyEndAt: pregnancyEnd, offspringId,
        inbreedingCoefficient: inbreedingCoeff, inbreedingWarning: inbreedingCoeff > 0.25,
      });
    });
  } catch (err: any) {
    if (err.statusCode) return res.status(err.statusCode).json({ error: err.error, message: err.message });
    logger.error('Breed error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR', message: 'Breeding failed' });
  }
});

// ─── GET /breed/active ────────────────────────────────────────────────────────

router.get('/active', async (req: AuthenticatedRequest, res: Response) => {
  const userId = req.user!.id;
  try {
    const rows = await queryMany<any>(
      `SELECT id, name, breed, status, pregnancy_end_at, recovery_end_at
       FROM animals WHERE owner_id = ? AND died_at IS NULL AND status IN ('pregnant','recovering')
       ORDER BY pregnancy_end_at ASC`,
      [userId]
    );
    res.json(rows.map(a => ({ id: a.id, name: a.name, breed: a.breed, status: a.status, pregnancyEndAt: a.pregnancy_end_at, recoveryEndAt: a.recovery_end_at })));
  } catch (err) {
    logger.error('GET /breed/active error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

export default router;
