import express from "express";
import jwt from "jsonwebtoken";
import { getConfig } from "../configLoader.js";
import { computeWorldSeedState } from "../worldSeed.js";
import { authMiddleware, JWT_SECRET } from "../middleware/auth.js";
import {
  ensureSeedEpoch,
  getGridCells,
  insertCell,
  getExistingCell,
  getTeamCooldown,
  getUserCooldown,
  upsertUserCooldown,
  getScores,
  getEconScores,
  addEconScore,
  getElementBonus,
  setElementBonus,
  getDbCreatedAt,
  getVictoryPoints,
} from "../db/gameDb.js";
import { computeCell, rowToCellPayload } from "../helpers/cell.js";

const router = express.Router();

// GET /api/config
router.get("/config", async (req, res) => {
  try {
    const worldSeed = await ensureSeedEpoch();
    const cfg = getConfig();
    const rot = cfg.databaseWipeoutIntervalSeconds;
    const ws = computeWorldSeedState(rot);

    let teamCooldownRemaining = 0;
    const team = typeof req.query.team === "string" ? req.query.team : undefined;
    if (team === "blue" || team === "red") {
      const bonus = await getElementBonus(worldSeed);
      const teamBonus = bonus[team] ?? 0;
      const effectiveCooldown = cfg.clickCooldownSeconds / (1 + teamBonus / 100);
      // Use per-user cooldown if auth token provided, else fall back to team-wide
      const authHeader = req.headers["authorization"];
      if (authHeader && authHeader.startsWith("Bearer ")) {
        try {
          const payload = jwt.verify(authHeader.slice(7), JWT_SECRET);
          const row = await getUserCooldown(worldSeed, payload.userId);
          if (row) {
            const secondsSince = (Date.now() - new Date(row.last_reveal).getTime()) / 1000;
            if (secondsSince < effectiveCooldown) {
              teamCooldownRemaining = Math.ceil(effectiveCooldown - secondsSince);
            }
          }
        } catch { /* invalid token — return 0 */ }
      } else {
        const row = await getTeamCooldown(worldSeed, team);
        if (row) {
          const secondsSince = (Date.now() - new Date(row.last_reveal).getTime()) / 1000;
          if (secondsSince < effectiveCooldown) {
            teamCooldownRemaining = Math.ceil(effectiveCooldown - secondsSince);
          }
        }
      }
    }

    res.json({
      clickCooldownSeconds: cfg.clickCooldownSeconds,
      databaseWipeoutIntervalSeconds: rot,
      debugModeForTeams: cfg.debugModeForTeams,
      configReloadIntervalSeconds: cfg.configReloadIntervalSeconds,
      worldSeed: ws.worldSeed,
      seedPeriodEndsAtUtc: ws.seedPeriodEndsAtUtc,
      seedPeriodStartsAtUtc: ws.seedPeriodStartsAtUtc,
      teamCooldownRemaining,
      resourceWorth: cfg.resourceWorth ?? { common: {}, rare: {} },
      elementWorth: cfg.elementWorth ?? {},
    });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "config_error" });
  }
});

// GET /api/grid/:seed
router.get("/grid/:seed", async (req, res) => {
  const seed = decodeURIComponent(req.params.seed || "");
  try {
    const worldSeed = await ensureSeedEpoch();
    if (seed !== worldSeed) {
      return res.status(410).json({
        error: "seed_expired",
        worldSeed,
        seedPeriodEndsAtUtc: computeWorldSeedState(
          getConfig().databaseWipeoutIntervalSeconds
        ).seedPeriodEndsAtUtc,
      });
    }
    const rows = await getGridCells(seed);
    res.json({ seed, cells: rows });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// POST /api/cell/reveal
router.post("/cell/reveal", authMiddleware, async (req, res) => {
  const seed = String(req.body?.seed ?? "");
  const team = req.user.team;          // taken from verified JWT, not request body
  const userId = req.user.userId;
  const x = Number(req.body?.x);
  const y = Number(req.body?.y);

  if (!seed || !Number.isInteger(x) || !Number.isInteger(y) || x < 0 || x >= 100 || y < 0 || y >= 100) {
    return res.status(400).json({ error: "invalid_body" });
  }

  try {
    const worldSeed = await ensureSeedEpoch();
    if (seed !== worldSeed) {
      return res.status(410).json({ error: "seed_expired", worldSeed });
    }

    const cfg = getConfig();
    if (cfg.clickCooldownSeconds > 0) {
      const bonus = await getElementBonus(worldSeed);
      const teamBonus = bonus[team] ?? 0;
      const effectiveCooldown = cfg.clickCooldownSeconds / (1 + teamBonus / 100);
      const cooldownRow = await getUserCooldown(worldSeed, userId);
      if (cooldownRow) {
        const secondsSince = (Date.now() - new Date(cooldownRow.last_reveal).getTime()) / 1000;
        if (secondsSince < effectiveCooldown) {
          return res.status(429).json({
            error: "cooldown_active",
            team,
            remainingSeconds: Math.ceil(effectiveCooldown - secondsSince),
            cooldownSeconds: effectiveCooldown,
          });
        }
      }
    }

    const cell = computeCell(seed, x, y);
    const planetJson = cell.planet ? JSON.stringify(cell.planet) : null;
    const inserted = await insertCell(seed, x, y, cell.exploitable, cell.hasPlanet, planetJson, team);

    if (inserted) {
      await upsertUserCooldown(worldSeed, userId, team);
      return res.json(rowToCellPayload(inserted));
    }

    const existing = await getExistingCell(seed, x, y);
    if (!existing) return res.status(500).json({ error: "insert_race" });

    if (existing.discovered_by !== team) {
      return res.status(409).json({
        error: "taken_by_other_team",
        discoveredBy: existing.discovered_by,
        cell: rowToCellPayload(existing),
      });
    }
    return res.json(rowToCellPayload(existing));
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// GET /api/econ-scores
router.get("/econ-scores", async (_req, res) => {
  try {
    const worldSeed = await ensureSeedEpoch();
    const scores = await getEconScores(worldSeed);
    res.json(scores);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// POST /api/econ-scores/tick  body: { seed, blue, red }
router.post("/econ-scores/tick", async (req, res) => {
  const seed  = String(req.body?.seed ?? "");
  const blue  = Number(req.body?.blue ?? 0);
  const red   = Number(req.body?.red  ?? 0);
  try {
    const worldSeed = await ensureSeedEpoch();
    if (seed !== worldSeed) return res.status(410).json({ error: "seed_expired", worldSeed });
    await addEconScore(worldSeed, "blue", blue);
    await addEconScore(worldSeed, "red",  red);
    const scores = await getEconScores(worldSeed);
    res.json(scores);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// GET /api/element-bonus
router.get("/element-bonus", async (_req, res) => {
  try {
    const worldSeed = await ensureSeedEpoch();
    const bonus = await getElementBonus(worldSeed);
    res.json(bonus);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// POST /api/element-bonus/tick  body: { seed, blue, red }
router.post("/element-bonus/tick", async (req, res) => {
  const seed = String(req.body?.seed ?? "");
  const blue = Number(req.body?.blue ?? 0);
  const red  = Number(req.body?.red  ?? 0);
  try {
    const worldSeed = await ensureSeedEpoch();
    if (seed !== worldSeed) return res.status(410).json({ error: "seed_expired", worldSeed });
    await setElementBonus(worldSeed, "blue", blue);
    await setElementBonus(worldSeed, "red",  red);
    const bonus = await getElementBonus(worldSeed);
    res.json(bonus);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// GET /api/db-info
router.get("/db-info", async (_req, res) => {
  try {
    const createdAt = await getDbCreatedAt();
    res.json({ createdAt });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// GET /api/victory-points
router.get("/victory-points", async (_req, res) => {
  try {
    const vp = await getVictoryPoints();
    res.json(vp);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

// GET /api/scores
router.get("/scores", async (_req, res) => {
  try {
    const worldSeed = await ensureSeedEpoch();
    const rows = await getScores(worldSeed);
    const scores = { blue: 0, red: 0 };
    for (const row of rows) {
      if (row.discovered_by === "blue") scores.blue = Number(row.cnt);
      if (row.discovered_by === "red") scores.red = Number(row.cnt);
    }
    res.json(scores);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "database_error" });
  }
});

export default router;