import express from "express";
import "dotenv/config";
import { getAccessToken } from "../lib/accessToken.js";

const router = express.Router();

function requireEnv(name) {
  const v = process.env[name];
  if (!v) throw new Error(`Missing required env var: ${name}`);
  return v;
}

const apikey = requireEnv("TRACK_ANALYSIS_API");
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const SUMMARY_CACHE_TTL_MS = 1000 * 60 * 60 * 24;
const summaryCache = new Map();

const getCacheKey = (token, scope) => `${scope}:${token}`;

const readCache = (key) => {
  const entry = summaryCache.get(key);
  if (!entry) return null;
  if (entry.expiresAt <= Date.now()) {
    summaryCache.delete(key);
    return null;
  }
  return entry.data;
};

const writeCache = (key, data) => {
  summaryCache.set(key, {
    data,
    expiresAt: Date.now() + SUMMARY_CACHE_TTL_MS,
  });
};

const purgeExpiredCache = () => {
  const now = Date.now();
  for (const [key, entry] of summaryCache.entries()) {
    if (entry.expiresAt <= now) {
      summaryCache.delete(key);
    }
  }
};

setInterval(purgeExpiredCache, 60 * 60 * 1000).unref?.();

const validRanges = ["short_term", "medium_term", "long_term"];

function getTimeRange(query) {
  return validRanges.includes(query.time_range) ? query.time_range : "short_term";
}

router.get("/top-tracks", async (req, res) => {
  const token = getAccessToken(req);
  if (!token) return res.status(401).json({ error: "Not logged in" });
  
  const timeRange = getTimeRange(req.query);

  const cacheKey = getCacheKey(token, `top-tracks:${timeRange}`);
  const cached = readCache(cacheKey);
  if (cached) {
    return res.json(cached);
  }

  try {
    const resp = await fetch(`https://api.spotify.com/v1/me/top/tracks?time_range=${timeRange}&limit=5`, {
      headers: { Authorization: `Bearer ${token}` },
    });
    const text = await resp.text();
    let data;

    try { data = JSON.parse(text); }
    catch { return res.status(500).json({ error: "Bad Spotify Response" }); }

    if (!resp.ok) return res.status(resp.status).json(data);

    if (data.items && Array.isArray(data.items)) {
      const analyzedItems = [];

      for (const item of data.items) {
        try {
          const analysisResp = await fetch(`https://track-analysis.p.rapidapi.com/pktx/spotify/${item.id}`, {
            method: "GET",
            headers: {
              "x-rapidapi-key": apikey,
              "x-rapidapi-host": "track-analysis.p.rapidapi.com"
            }
          });
          const analysisData = analysisResp.ok ? await analysisResp.json() : null;

          analyzedItems.push({
            id: item.id,
            name: item.name,
            artist: item.artists[0]?.name,
            image: item.album?.images[0]?.url,
            soundnet_analysis: analysisData
          });

          await delay(1100);

        } catch (innerErr) {
          console.error(`Failed: ${item.name}`);
          analyzedItems.push(item);
        }
      }

      data.items = analyzedItems;
      data.time_range = timeRange;
    }

    writeCache(cacheKey, data);
    res.json(data);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: err.message });
  }
});

router.get("/top-artists", async (req, res) => {
  const token = getAccessToken(req);
  if (!token) return res.status(401).json({ error: "Not logged in" });

  const timeRange = getTimeRange(req.query);

  const cacheKey = getCacheKey(token, `top-artists:${timeRange}`);
  const cached = readCache(cacheKey);
  if (cached) {
    return res.json(cached);
  }

  try {
    const resp = await fetch(`https://api.spotify.com/v1/me/top/artists?time_range=${timeRange}&limit=5`, {
      headers: { Authorization: `Bearer ${token}` },
    });

    const text = await resp.text();
    let data;
    try {
      data = JSON.parse(text);
    } catch {
      console.error("Spotify returned non-JSON:", text);
      return res.status(500).json({
        error: "Spotify returned non-JSON response",
        raw: text,
        status: resp.status,
      });
    }

    if (!resp.ok) return res.status(resp.status).json(data);

    data.time_range = timeRange;
    writeCache(cacheKey, data);
    res.json(data);
  } catch (err) {
    console.error("Fetch failed:", err);
    res.status(500).json({ error: "Failed to fetch top artists", details: err.message });
  }
});

router.get("/genre-stats", async (req, res) => {
  const token = getAccessToken(req);
  if (!token) return res.status(401).json({ error: "Not logged in" });

  const timeRange = getTimeRange(req.query);

  const genresCacheKey  = getCacheKey(token, `genre-stats:${timeRange}`);
  const artistsCacheKey = getCacheKey(token, `top-artists:${timeRange}`);

  const cachedGenres = readCache(genresCacheKey);
  if (cachedGenres) {
    return res.json(cachedGenres);
  }

  try {
    let artistsData = readCache(artistsCacheKey);

    if (!artistsData) {
      const resp = await fetch(`https://api.spotify.com/v1/me/top/artists?time_range=${timeRange}&limit=5`, {
        headers: { Authorization: `Bearer ${token}` },
      });
    
      const text = await resp.text();
      let parsed;
    
      try {
        parsed = JSON.parse(text);
      } catch {
        return res.status(500).json({ error: "Bad Spotify Response" });
      }
    
      if (!resp.ok) return res.status(resp.status).json(parsed);
    
      parsed.time_range = timeRange;
      writeCache(artistsCacheKey, parsed);
      artistsData = parsed;
    }

    const genreCounts = {};
    let totalGenres = 0;

    if (artistsData.items && Array.isArray(artistsData.items)) {
      for (const artist of artistsData.items) {
        for (const genre of artist.genres) {
          genreCounts[genre] = (genreCounts[genre] || 0) + 1;
          totalGenres++;
        }
      }
    }

    if (totalGenres === 0) {
      const emptyResult = { genres: {}, time_range: timeRange };
      writeCache(genresCacheKey, emptyResult);
      return res.json(emptyResult);
    }

    const genrePercentages = {};
    for (const [genre, count] of Object.entries(genreCounts)) {
      genrePercentages[genre] = Math.round((count / totalGenres) * 100);
    }

    const result = { genres: genrePercentages, time_range: timeRange };
    writeCache(genresCacheKey, result);
    res.json(result);

  } catch (err) {
    console.error(err);
    res.status(500).json({ error: err.message });
  }
});

export default router;
