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 { BUILDING_DEFINITIONS, BuildingType } from '@ranchlands/shared';
import { v4 as uuidv4 } from 'uuid';

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

function mapBuilding(b: any) {
  return {
    id: b.id, ranchId: b.ranch_id, buildingType: b.building_type,
    plotPosition: b.plot_position, status: b.status,
    completeAt: b.complete_at, builtAt: b.built_at,
    definition: BUILDING_DEFINITIONS[b.building_type as BuildingType],
  };
}

// ─── GET /ranch/me/dashboard ──────────────────────────────────────────────────

router.get('/me/dashboard', async (req: AuthenticatedRequest, res: Response) => {
  const userId = req.user!.id;
  try {
    const ranch   = await queryOne<any>('SELECT * FROM ranches WHERE owner_id = ?', [userId]);
    if (!ranch) return res.status(404).json({ error: 'NOT_FOUND' });

    const user    = await queryOne<any>('SELECT gold_balance, prestige_points FROM users WHERE id = ?', [userId]);
    const total   = await queryOne<any>('SELECT COUNT(*) as cnt FROM animals WHERE owner_id = ? AND died_at IS NULL', [userId]);
    const needsFeed = await queryOne<any>('SELECT COUNT(*) as cnt FROM animals WHERE owner_id = ? AND died_at IS NULL AND `condition` < 30', [userId]);
    const pregnant  = await queryOne<any>(`SELECT COUNT(*) as cnt FROM animals WHERE owner_id = ? AND died_at IS NULL AND status = 'pregnant'`, [userId]);

    const alerts: any[] = [];

    const sickAnimals = await queryMany<any>('SELECT id, name FROM animals WHERE owner_id = ? AND died_at IS NULL AND health < 40 LIMIT 3', [userId]);
    for (const a of sickAnimals) alerts.push({ type: 'animal_sick', message: `${a.name} needs medical attention`, animalId: a.id, urgency: 'high' });

    const readyFemales = await queryMany<any>(`SELECT id, name FROM animals WHERE owner_id = ? AND died_at IS NULL AND sex = 'female' AND stage IN ('adult','elder') AND status = 'healthy' LIMIT 3`, [userId]);
    for (const a of readyFemales) alerts.push({ type: 'ready_to_breed', message: `${a.name} is ready to breed`, animalId: a.id, urgency: 'low' });

    const closingShows = await queryMany<any>(`SELECT id, name FROM shows WHERE status = 'open' AND entry_closes_at < DATE_ADD(NOW(), INTERVAL 4 HOUR) LIMIT 2`);
    for (const s of closingShows) alerts.push({ type: 'show_closing', message: `${s.name} closes soon`, showId: s.id, urgency: 'medium' });

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

    res.json({
      ranch: { id: ranch.id, name: ranch.name, prestigeLevel: ranch.prestige_level },
      goldBalance: parseInt(user?.gold_balance || '0'),
      herdSummary: {
        total: parseInt(total?.cnt || '0'),
        needingFeed: parseInt(needsFeed?.cnt || '0'),
        pregnant: parseInt(pregnant?.cnt || '0'),
      },
      alerts: alerts.slice(0, 8),
      recentResults: recentResults.map(r => ({
        showName: r.show_name, tier: r.tier,
        score: r.score ? parseFloat(r.score) : null, rank: r.rank,
      })),
    });
  } catch (err) {
    logger.error('GET /ranch/me/dashboard error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

// ─── GET /ranch/me ────────────────────────────────────────────────────────────

router.get('/me', async (req: AuthenticatedRequest, res: Response) => {
  const userId = req.user!.id;
  try {
    const ranch = await queryOne<any>('SELECT * FROM ranches WHERE owner_id = ?', [userId]);
    if (!ranch) return res.status(404).json({ error: 'NOT_FOUND' });

    const buildings = await queryMany<any>('SELECT * FROM buildings WHERE ranch_id = ?', [ranch.id]);
    const herdCount = await queryOne<any>('SELECT COUNT(*) as cnt FROM animals WHERE owner_id = ? AND died_at IS NULL', [userId]);

    let herdCapacity = 15;
    for (const b of buildings) {
      if (b.status === 'active') {
        const def = BUILDING_DEFINITIONS[b.building_type as BuildingType];
        if (def) herdCapacity += def.herdCapacityBonus;
      }
    }

    const herdSize = parseInt(herdCount?.cnt || '0');
    const dailyUpkeep = herdSize * 2 + buildings.filter((b: any) => b.status === 'active').length * 5 + 10;

    res.json({
      id: ranch.id, ownerId: ranch.owner_id, name: ranch.name,
      description: ranch.description, plotCount: ranch.plot_count,
      maxPlotCount: ranch.max_plot_count, herdCapacity, herdCount: herdSize,
      lastUpkeepAt: ranch.last_upkeep_at, debtFlag: !!ranch.debt_flag,
      prestigeLevel: ranch.prestige_level, dailyUpkeep,
      buildings: buildings.map(mapBuilding), createdAt: ranch.created_at,
    });
  } catch (err) {
    logger.error('GET /ranch/me error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

// ─── GET /ranch/:id (public profile) ─────────────────────────────────────────

router.get('/:id', async (req: AuthenticatedRequest, res: Response) => {
  const { id } = req.params;
  // Skip "me" — handled above
  if (id === 'me') return;

  try {
    const ranch = await queryOne<any>(`
      SELECT r.*, u.username as owner_username
      FROM ranches r JOIN users u ON u.id = r.owner_id WHERE r.id = ?
    `, [id]);
    if (!ranch) return res.status(404).json({ error: 'NOT_FOUND' });

    const herdCount = await queryOne<any>('SELECT COUNT(*) as cnt FROM animals WHERE ranch_id = ? AND died_at IS NULL', [id]);
    res.json({
      id: ranch.id, name: ranch.name, ownerUsername: ranch.owner_username,
      description: ranch.description, prestigeLevel: ranch.prestige_level,
      herdCount: parseInt(herdCount?.cnt || '0'), createdAt: ranch.created_at,
    });
  } catch (err) {
    logger.error('GET /ranch/:id error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

// ─── PATCH /ranch/me ─────────────────────────────────────────────────────────

router.patch('/me', async (req: AuthenticatedRequest, res: Response) => {
  const parsed = z.object({
    name: z.string().min(3).max(100).optional(),
    description: z.string().max(500).optional(),
  }).safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'VALIDATION_ERROR' });

  const userId = req.user!.id;
  const sets: string[] = [];
  const params: unknown[] = [];

  if (parsed.data.name !== undefined)        { sets.push('name = ?');        params.push(parsed.data.name); }
  if (parsed.data.description !== undefined) { sets.push('description = ?'); params.push(parsed.data.description); }
  if (!sets.length) return res.json({ success: true });

  params.push(userId);
  try {
    await exec(`UPDATE ranches SET ${sets.join(', ')} WHERE owner_id = ?`, params);
    res.json({ success: true });
  } catch (err) {
    logger.error('PATCH /ranch/me error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

// ─── POST /ranch/me/buildings ─────────────────────────────────────────────────

router.post('/me/buildings', async (req: AuthenticatedRequest, res: Response) => {
  const parsed = z.object({
    buildingType: z.nativeEnum(BuildingType),
    plotPosition: z.number().int().min(0).max(19),
  }).safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: 'VALIDATION_ERROR' });

  const { buildingType, plotPosition } = parsed.data;
  const userId = req.user!.id;
  const def = BUILDING_DEFINITIONS[buildingType];

  try {
    await withTransaction(async (client) => {
      const [[ranchRows]] = await client.execute('SELECT * FROM ranches WHERE owner_id = ? FOR UPDATE', [userId]) as any[];
      const r = (ranchRows as any[])[0];
      if (!r) throw { statusCode: 404, error: 'NOT_FOUND' };
      if (plotPosition >= r.plot_count) throw { statusCode: 400, error: 'INVALID_PLOT', message: 'Plot not yet unlocked' };

      const [[existRows]] = await client.execute('SELECT id FROM buildings WHERE ranch_id = ? AND plot_position = ?', [r.id, plotPosition]) as any[];
      if ((existRows as any[]).length) throw { statusCode: 409, error: 'PLOT_OCCUPIED', message: 'Plot already occupied' };

      const [deduct] = await client.execute(
        'UPDATE users SET gold_balance = gold_balance - ? WHERE id = ? AND gold_balance >= ?',
        [def.cost, userId, def.cost]
      ) as any[];
      if ((deduct as any).affectedRows === 0) throw { statusCode: 400, error: 'INSUFFICIENT_GOLD', message: `${def.name} costs ${def.cost} Gold` };

      const completeAt = new Date(Date.now() + def.constructionHours * 60 * 60 * 1000);
      const buildingId = uuidv4();

      await client.execute(
        `INSERT INTO buildings (id, ranch_id, building_type, plot_position, status, complete_at) VALUES (?, ?, ?, ?, 'constructing', ?)`,
        [buildingId, r.id, buildingType, plotPosition, completeAt]
      );

      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, -def.cost, (userRow as any[])[0].gold_balance, `Built ${def.name}`]
      );

      res.status(201).json({
        building: { id: buildingId, ranchId: r.id, buildingType, plotPosition, status: 'constructing', completeAt, definition: def },
        message: `${def.name} construction started. Ready in ${def.constructionHours} hours.`,
      });
    });
  } catch (err: any) {
    if (err.statusCode) return res.status(err.statusCode).json({ error: err.error, message: err.message });
    logger.error('POST /ranch/me/buildings error', err);
    res.status(500).json({ error: 'INTERNAL_ERROR' });
  }
});

export default router;
