import { Router } from 'express';
import { prisma } from '../db.js';
import { requireAuth } from '../middleware.js';
import { getDropFeed, pushDrop } from '../feed.js';
import { toCentsBigInt } from '../cents.js';

const router = Router();

router.get('/', (_req, res) => {
  res.json({ drops: getDropFeed() });
});

/**
 * Announce case drop(s) to the live feed (after client spin finishes).
 * For multi-opens: send all inventoryItemIds — only the best drop is shown,
 * with count of how many times that item appeared (e.g. x3).
 *
 * Respin flow:
 * - First spin (discarded): body.snapshotItems (no inventory left)
 * - Final spin: body.inventoryItemIds + body.respin=true
 */
router.post('/announce', requireAuth, async (req, res) => {
  try {
    const caseName = String(req.body.caseName || '').slice(0, 80);
    const respin = Boolean(req.body.respin);
    const snapshotItems = Array.isArray(req.body.snapshotItems)
      ? req.body.snapshotItems
      : null;

    // Discarded first roll (respin preview) — announce from client snapshot.
    // Prefer compact payload: snapshotBest + openCount (+ optional count).
    if (snapshotItems?.length || req.body.snapshotBest) {
      const user = await prisma.user.findUnique({
        where: { id: req.session.userId },
        select: { username: true, avatarUrl: true },
      });
      if (!user) return res.status(401).json({ error: 'Unauthorized' });

      const normalizeOne = (raw) => ({
        id: Number(raw?.id) || 0,
        name: String(raw?.name || '').slice(0, 120),
        imageUrl: String(raw?.imageUrl || '').slice(0, 500),
        rarity: String(raw?.rarity || '').slice(0, 40),
        valueCents: String(raw?.valueCents ?? raw?.marketValue ?? '0'),
        wear: raw?.wear ? String(raw.wear).slice(0, 40) : '',
        floatValue: Number(raw?.floatValue) || 0,
        paintSeed: Number(raw?.paintSeed) || 0,
      });

      let best;
      let openCount;
      let count;

      if (req.body.snapshotBest) {
        best = normalizeOne(req.body.snapshotBest);
        if (!best.id || !best.name) {
          return res.status(400).json({ error: 'Invalid snapshot best item' });
        }
        openCount = Math.max(1, Math.floor(Number(req.body.openCount) || 1));
        count = Math.max(1, Math.min(openCount, Math.floor(Number(req.body.count) || 1)));
      } else {
        const normalized = snapshotItems.map(normalizeOne).filter((it) => it.id && it.name);
        if (!normalized.length) {
          return res.status(400).json({ error: 'Invalid snapshot items' });
        }
        best = normalized[0];
        for (const it of normalized) {
          if (toCentsBigInt(it.valueCents) > toCentsBigInt(best.valueCents)) best = it;
        }
        openCount = normalized.length;
        count = normalized.filter((it) => it.id === best.id).length;
      }

      const drop = pushDrop({
        source: 'case',
        caseName,
        respin: false,
        count,
        openCount,
        inventoryIds: [],
        username: user.username,
        avatarUrl: user.avatarUrl || '',
        item: {
          inventoryId: null,
          id: best.id,
          name: best.name,
          imageUrl: best.imageUrl,
          rarity: best.rarity,
          marketValue: best.valueCents,
          valueCents: best.valueCents,
          wear: best.wear,
          floatValue: best.floatValue,
          paintSeed: best.paintSeed,
        },
      });

      return res.json({ drop });
    }

    let ids = [];
    if (Array.isArray(req.body.inventoryItemIds)) {
      ids = req.body.inventoryItemIds.map(Number).filter(Boolean);
    } else if (req.body.inventoryItemId) {
      ids = [Number(req.body.inventoryItemId)].filter(Boolean);
    }
    ids = [...new Set(ids)];

    if (!ids.length) {
      return res.status(400).json({ error: 'inventoryItemId(s) required' });
    }

    const invItems = await prisma.inventoryItem.findMany({
      where: { id: { in: ids }, userId: req.session.userId },
      include: {
        item: true,
        user: { select: { username: true, avatarUrl: true } },
      },
    });

    if (invItems.length !== ids.length) {
      return res.status(404).json({ error: 'Inventory item not found' });
    }

    const now = Date.now();
    for (const inv of invItems) {
      const ageMs = now - new Date(inv.obtainedAt).getTime();
      if (ageMs > 2 * 60 * 1000) {
        return res.status(400).json({ error: 'Drop too old to announce' });
      }
    }

    // Best drop = highest instance value (tie-break: first in batch)
    let best = invItems[0];
    for (const inv of invItems) {
      if (toCentsBigInt(inv.valueCents) > toCentsBigInt(best.valueCents)) best = inv;
    }

    const count = invItems.filter((inv) => inv.itemId === best.itemId).length;

    const drop = pushDrop({
      source: 'case',
      caseName,
      respin,
      count,
      openCount: invItems.length,
      inventoryIds: invItems.map((i) => i.id),
      username: best.user.username,
      avatarUrl: best.user.avatarUrl || '',
      item: {
        inventoryId: best.id,
        id: best.item.id,
        name: best.item.name,
        imageUrl: best.item.imageUrl,
        rarity: best.item.rarity,
        marketValue: best.valueCents,
        valueCents: best.valueCents,
        wear: best.wear,
        floatValue: best.floatValue,
        paintSeed: best.paintSeed,
      },
    });

    res.json({ drop });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Failed to announce drop' });
  }
});

export default router;
