import { Router, Response } from 'express';
import { queryOne, queryMany, exec, withTransaction } from '../db/pool';
import { authenticate, AuthenticatedRequest } from '../middleware/auth';
import { logger } from '../lib/logger';
import { v4 as uuidv4 } from 'uuid';

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

const ANIMAL_SELECT = `
  SELECT a.*,
    ap.weight_score, ap.milk_yield_score, ap.growth_rate_score,
    ap.temperament_score, ap.coat_quality_score, ap.fertility_score,
    ap.hardiness_score, ap.show_potential_score,
    ag.genotype_tested
  FROM animals a
  LEFT JOIN animal_phenotypes ap ON ap.animal_id = a.id
  LEFT JOIN animal_genotypes ag  ON ag.animal_id  = a.id
  WHERE a.died_at IS NULL
`;

function mapAnimal(row: any) {
  return {
    id: row.id, ownerId: row.owner_id, ranchId: row.ranch_id,
    name: row.name, breed: row.breed, sex: row.sex,
    bornAt: row.born_at, diedAt: row.died_at, stage: row.stage,
    health: parseFloat(row.health), condition: parseFloat(row.condition),
    status: row.status, pregnancyEndAt: row.pregnancy_end_at,
    recoveryEndAt: row.recovery_end_at, sireId: row.sire_id, damId: row.dam_id,
    inbreedingCoefficient: parseFloat(row.inbreeding_coefficient),
    rarityTier: row.rarity_tier, lastFedAt: row.last_fed_at, createdAt: row.created_at,
    genotypeTested: !!row.genotype_tested,
    phenotype: row.weight_score != null ? {
      weightScore:       parseFloat(row.weight_score),
      milkYieldScore:    parseFloat(row.milk_yield_score),
      growthRateScore:   parseFloat(row.growth_rate_score),
      temperamentScore:  parseFloat(row.temperament_score),
      coatQualityScore:  parseFloat(row.coat_quality_score),
      fertilityScore:    parseFloat(row.fertility_score),
      hardinessScore:    parseFloat(row.hardiness_score),
      showPotentialScore:parseFloat(row.show_potential_score),
    } : null,
  };
}

// ─── GET /herd ────────────────────────────────────────────────────────────────

router.get('/', async (req: AuthenticatedRequest, res: Response) => {
  const { stage, status, breed, rarity, sort = 'name', page = '1', pageSize = '20' } = req.query;
  const userId = req.user!.id;
  const offset = (parseInt(page as string) - 1) * parseInt(pageSize as string);

  const conditions: string[] = ['a.owner_id = ?'];
  const params: unknown[] = [userId];

  if (stage)  { conditions.push('a.stage = ?');        params.push(stage); }
  if (status) { conditions.push('a.status = ?');       params.push(status); }
  if (breed)  { conditions.push('a.breed = ?');        params.push(breed); }
  if (rarity) { conditions.push('a.rarity_tier = ?');  params.push(rarity); }

  const where = conditions.join(' AND ');
  const sortMap: Record<string, string> = {
    name: 'a.name ASC', age: 'a.born_at ASC', condition: 'a.`condition` DESC',
    rarity: `FIELD(a.rarity_tier,'legendary','rare','uncommon','common')`,
  };
  const orderBy = sortMap[sort as string] || 'a.name ASC';

  try {
    const countRes = await queryOne<any>(
      `SELECT COUNT(*) as cnt FROM animals a WHERE ${where} AND a.died_at IS NULL`,
      params
    );
    const total = parseInt(countRes?.cnt || '0');

    const animals = await queryMany<any>(
      `${ANIMAL_SELECT} AND ${where} ORDER BY ${orderBy} LIMIT ? OFFSET ?`,
      [...params, parseInt(pageSize as string), offset]
    );

    res.json({ data: animals.map(mapAnimal), total, page: parseInt(page as string), pageSize: parseInt(pageSize as string), hasMore: offset + animals.length < total });
  } catch (err) {
    logger.error('GET /herd error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR', message: 'Failed to fetch herd' });
  }
});

// ─── GET /herd/:id ────────────────────────────────────────────────────────────

router.get('/:id', async (req: AuthenticatedRequest, res: Response) => {
  const { id } = req.params;
  const userId  = req.user!.id;

  try {
    const animal = await queryOne<any>(`${ANIMAL_SELECT} AND a.id = ?`, [id]);
    if (!animal) return res.status(404).json({ error: 'NOT_FOUND', message: 'Animal not found' });

    const showHistory = await queryMany<any>(`
      SELECT se.score, se.rank, s.name as show_name, s.tier, s.judged_at
      FROM show_entries se JOIN shows s ON s.id = se.show_id
      WHERE se.animal_id = ? AND s.status = 'completed'
      ORDER BY s.judged_at DESC LIMIT 5
    `, [id]);

    const sire = animal.sire_id ? await queryOne<any>(`${ANIMAL_SELECT} AND a.id = ?`, [animal.sire_id]) : null;
    const dam  = animal.dam_id  ? await queryOne<any>(`${ANIMAL_SELECT} AND a.id = ?`, [animal.dam_id])  : null;

    res.json({
      ...mapAnimal(animal),
      isOwner: animal.owner_id === userId,
      showHistory: showHistory.map((s: any) => ({ showName: s.show_name, tier: s.tier, score: s.score ? parseFloat(s.score) : null, rank: s.rank, judgedAt: s.judged_at })),
      sire: sire ? mapAnimal(sire) : null,
      dam:  dam  ? mapAnimal(dam)  : null,
    });
  } catch (err) {
    logger.error('GET /herd/:id error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR', message: 'Failed to fetch animal' });
  }
});

// ─── POST /herd/:id/feed ──────────────────────────────────────────────────────

router.post('/:id/feed', async (req: AuthenticatedRequest, res: Response) => {
  const { id } = req.params;
  const userId  = req.user!.id;
  const COST    = 5;

  try {
    const animal = await queryOne<any>('SELECT * FROM animals WHERE id = ? AND owner_id = ? AND died_at IS NULL', [id, userId]);
    if (!animal) return res.status(404).json({ error: 'NOT_FOUND' });
    if (parseFloat(animal.condition) >= 95) return res.status(400).json({ error: 'ALREADY_FED', message: 'Animal is already well-fed' });

    await withTransaction(async (client) => {
      const [deduct] = await client.execute(
        'UPDATE users SET gold_balance = gold_balance - ? WHERE id = ? AND gold_balance >= ?',
        [COST, userId, COST]
      ) as any[];

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

      const newCondition = Math.min(100, parseFloat(animal.condition) + 25);
      const newHealth    = Math.min(100, parseFloat(animal.health) + 5);

      await client.execute(
        `UPDATE animals SET \`condition\` = ?, health = ?, last_fed_at = NOW(),
         status = IF(status = 'neglected', 'healthy', status), updated_at = NOW() WHERE id = ?`,
        [newCondition, newHealth, id]
      );

      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, -COST, (userRow as any).gold_balance, `Fed: ${animal.name}`]
      );
    });

    res.json({ success: true, message: `${animal.name} has been fed` });
  } catch (err: any) {
    if (err.statusCode) return res.status(err.statusCode).json({ error: err.error, message: err.message });
    logger.error('Feed error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

// ─── POST /herd/:id/treat ─────────────────────────────────────────────────────

router.post('/:id/treat', async (req: AuthenticatedRequest, res: Response) => {
  const { id } = req.params;
  const userId  = req.user!.id;
  const COST    = 50;

  try {
    const animal = await queryOne<any>('SELECT * FROM animals WHERE id = ? AND owner_id = ? AND died_at IS NULL', [id, userId]);
    if (!animal) return res.status(404).json({ error: 'NOT_FOUND' });
    if (parseFloat(animal.health) >= 90) return res.status(400).json({ error: 'NOT_SICK', message: 'Animal is not sick enough to treat' });

    await withTransaction(async (client) => {
      const [deduct] = await client.execute(
        'UPDATE users SET gold_balance = gold_balance - ? WHERE id = ? AND gold_balance >= ?',
        [COST, userId, COST]
      ) as any[];

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

      await client.execute(
        'UPDATE animals SET health = LEAST(100, health + 40), updated_at = NOW() WHERE id = ?',
        [id]
      );

      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, -COST, (userRow as any).gold_balance, `Treated: ${animal.name}`]
      );
    });

    res.json({ success: true, message: `${animal.name} has been treated` });
  } catch (err: any) {
    if (err.statusCode) return res.status(err.statusCode).json({ error: err.error, message: err.message });
    logger.error('Treat error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

// ─── POST /herd/:id/retire ────────────────────────────────────────────────────

router.post('/:id/retire', async (req: AuthenticatedRequest, res: Response) => {
  const { id } = req.params;
  const userId  = req.user!.id;
  const REWARD  = 25;

  try {
    const animal = await queryOne<any>('SELECT * FROM animals WHERE id = ? AND owner_id = ? AND died_at IS NULL', [id, userId]);
    if (!animal) return res.status(404).json({ error: 'NOT_FOUND' });
    if (animal.stage !== 'elder') return res.status(400).json({ error: 'NOT_ELDER' });
    if (animal.status === 'retired') return res.status(400).json({ error: 'ALREADY_RETIRED' });

    await withTransaction(async (client) => {
      await client.execute(`UPDATE animals SET status = 'retired', died_at = NOW() WHERE id = ?`, [id]);
      await client.execute('UPDATE users SET gold_balance = gold_balance + ? WHERE id = ?', [REWARD, userId]);
      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', 'reward', ?, ?)`,
        [uuidv4(), userId, REWARD, (userRow as any).gold_balance, `Retired: ${animal.name}`]
      );
    });

    res.json({ success: true, message: `${animal.name} retired. You received ${REWARD} Gold.` });
  } catch (err: any) {
    if (err.statusCode) return res.status(err.statusCode).json({ error: err.error, message: err.message });
    logger.error('Retire error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

export default router;
