const express = require('express');
const router = express.Router();
const axios = require('axios');
const requireAuth = require('../middleware/requireAuth');
const cache = require('../utils/cache');
const { fetchSonarrHistory, fetchRadarrHistory, classifySonarrEvent, classifyRadarrEvent } = require('../utils/historyFetcher');
const { getSonarrInstances, getRadarrInstances } = require('../utils/config');
const sanitizeError = require('../utils/sanitizeError');

// Re-use the same tag/cover-art helpers as dashboard.js by importing them
// from a shared location.  For now they are inlined here to keep dashboard.js
// untouched (zero-conflict v1 merges).  If these diverge they can be extracted
// into server/utils/dashboardHelpers.js in a later refactor.

function getCoverArt(item) {
  if (!item || !item.images) return null;
  const poster = item.images.find(img => img.coverType === 'poster');
  if (poster) return poster.remoteUrl || poster.url || null;
  const fanart = item.images.find(img => img.coverType === 'fanart');
  return fanart ? (fanart.remoteUrl || fanart.url || null) : null;
}

function sanitizeTagLabel(input) {
  if (!input) return '';
  return input.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
}

function tagMatchesUser(tag, username) {
  if (!tag || !username) return false;
  const tagLower = tag.toLowerCase();
  if (tagLower === username) return true;
  if (tagLower === sanitizeTagLabel(username)) return true;
  return false;
}

function extractAllTags(tags, tagMap) {
  if (!tags || tags.length === 0) return [];
  if (tagMap) return tags.map(id => tagMap.get(id)).filter(Boolean);
  return tags.map(t => t && t.label).filter(Boolean);
}

function extractUserTag(tags, tagMap, username) {
  const allLabels = extractAllTags(tags, tagMap);
  if (!allLabels.length) return null;
  if (username) {
    const match = allLabels.find(label => tagMatchesUser(label, username));
    if (match) return match;
  }
  return null;
}

async function getEmbyUsers() {
  const cached = cache.get('emby:users');
  if (cached) return cached;
  try {
    const embyUrl = process.env.EMBY_URL;
    const embyKey = process.env.EMBY_API_KEY;
    if (!embyUrl || !embyKey) return new Map();
    const res = await axios.get(`${embyUrl}/Users`, { params: { api_key: embyKey } });
    const users = res.data || [];
    const map = new Map();
    for (const u of users) {
      if (!u.Name) continue;
      const lower = u.Name.toLowerCase();
      map.set(lower, u.Name);
      map.set(sanitizeTagLabel(lower), u.Name);
    }
    cache.set('emby:users', map, 60000);
    return map;
  } catch (err) {
    console.error('[History] Failed to fetch Emby users:', err.message);
    return new Map();
  }
}

function buildTagBadges(allTags, embyUserMap) {
  return allTags.map(label => {
    const lower = label.toLowerCase();
    const sanitized = sanitizeTagLabel(label);
    const matchedUser = embyUserMap.get(lower) || embyUserMap.get(sanitized) || null;
    return { label, matchedUser };
  });
}

function getSonarrLink(series) {
  if (!series || !series._instanceUrl || !series.titleSlug) return null;
  return `${series._instanceUrl}/series/${series.titleSlug}`;
}

function getRadarrLink(movie) {
  if (!movie || !movie._instanceUrl || !movie.titleSlug) return null;
  return `${movie._instanceUrl}/movie/${movie.titleSlug}`;
}

/**
 * GET /api/history/recent
 *
 * Returns Sonarr/Radarr history records (imported + failed) for the
 * authenticated user, filtered to the last RECENT_COMPLETED_DAYS days
 * (default 7, overridable via env or ?days= query param).
 *
 * Response shape:
 * {
 *   user: string,
 *   isAdmin: boolean,
 *   days: number,
 *   history: HistoryItem[]
 * }
 *
 * HistoryItem shape:
 * {
 *   type: 'series'|'movie',
 *   outcome: 'imported'|'failed',
 *   title: string,            // sourceTitle from arr record
 *   seriesName?: string,      // series.title (Sonarr)
 *   movieName?: string,       // movie.title (Radarr)
 *   coverArt: string|null,
 *   completedAt: string,      // ISO date string from arr record
 *   quality: string|null,
 *   instanceName: string,     // arr instance name
 *   arrLink: string|null,     // link to item in Sonarr/Radarr UI
 *   allTags: string[],
 *   matchedUserTag: string|null,
 *   // admin-only:
 *   arrRecordId?: number,
 *   failureMessage?: string,
 * }
 */
router.get('/recent', requireAuth, async (req, res) => {
  try {
    const user = req.user;
    const username = user.name.toLowerCase();
    const isAdmin = !!user.isAdmin;
    const showAll = isAdmin && req.query.showAll === 'true';

    const defaultDays = parseInt(process.env.RECENT_COMPLETED_DAYS, 10) || 7;
    const requestedDays = parseInt(req.query.days, 10);
    const days = (requestedDays > 0 && requestedDays <= 90) ? requestedDays : defaultDays;

    const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);

    // Fetch tag maps and history in parallel
    const sonarrInstances = getSonarrInstances();
    const radarrInstances = getRadarrInstances();

    const [sonarrHistory, radarrHistory, embyUserMap] = await Promise.all([
      fetchSonarrHistory(since),
      fetchRadarrHistory(since),
      showAll ? getEmbyUsers() : Promise.resolve(new Map())
    ]);

    // Build tag maps from the cached poll data where available,
    // falling back to what's embedded in history records
    const sonarrTagsData = cache.get('poll:sonarr-tags') || [];
    const radarrTagsData = cache.get('poll:radarr-tags') || [];
    const sonarrTagMap = new Map(sonarrTagsData.flatMap(t => t.data || []).map(t => [t.id, t.label]));
    const radarrTagMap = new Map(radarrTagsData.map(t => [t.id, t.label]));

    const historyItems = [];

    // --- Sonarr history ---
    for (const record of sonarrHistory) {
      try {
        const outcome = classifySonarrEvent(record.eventType);
        if (outcome === 'other') continue;

        const series = record.series;
        if (!series) continue;

        const allTags = extractAllTags(series.tags, sonarrTagMap);
        const matchedUserTag = extractUserTag(series.tags, sonarrTagMap, username);
        const hasAnyTag = allTags.length > 0;

        if (!(showAll ? hasAnyTag : !!matchedUserTag)) continue;

        const quality = record.quality && record.quality.quality && record.quality.quality.name
          ? record.quality.quality.name
          : null;

        const item = {
          type: 'series',
          outcome,
          title: record.sourceTitle || record.title || series.title,
          seriesName: series.title,
          coverArt: getCoverArt(series),
          completedAt: record.date,
          quality,
          instanceName: record._instanceName || null,
          arrLink: getSonarrLink(series),
          allTags,
          matchedUserTag: matchedUserTag || null,
          tagBadges: showAll ? buildTagBadges(allTags, embyUserMap) : undefined
        };

        if (isAdmin) {
          item.arrRecordId = record.id;
          if (outcome === 'failed' && record.data && record.data.message) {
            item.failureMessage = record.data.message;
          }
        }

        historyItems.push(item);
      } catch (err) {
        console.error('[History] Error processing Sonarr record:', err.message);
      }
    }

    // --- Radarr history ---
    for (const record of radarrHistory) {
      try {
        const outcome = classifyRadarrEvent(record.eventType);
        if (outcome === 'other') continue;

        const movie = record.movie;
        if (!movie) continue;

        const allTags = extractAllTags(movie.tags, radarrTagMap);
        const matchedUserTag = extractUserTag(movie.tags, radarrTagMap, username);
        const hasAnyTag = allTags.length > 0;

        if (!(showAll ? hasAnyTag : !!matchedUserTag)) continue;

        const quality = record.quality && record.quality.quality && record.quality.quality.name
          ? record.quality.quality.name
          : null;

        const item = {
          type: 'movie',
          outcome,
          title: record.sourceTitle || record.title || movie.title,
          movieName: movie.title,
          coverArt: getCoverArt(movie),
          completedAt: record.date,
          quality,
          instanceName: record._instanceName || null,
          arrLink: getRadarrLink(movie),
          allTags,
          matchedUserTag: matchedUserTag || null,
          tagBadges: showAll ? buildTagBadges(allTags, embyUserMap) : undefined
        };

        if (isAdmin) {
          item.arrRecordId = record.id;
          if (outcome === 'failed' && record.data && record.data.message) {
            item.failureMessage = record.data.message;
          }
        }

        historyItems.push(item);
      } catch (err) {
        console.error('[History] Error processing Radarr record:', err.message);
      }
    }

    // Sort newest first
    historyItems.sort((a, b) => new Date(b.completedAt) - new Date(a.completedAt));

    console.log(`[History] Returning ${historyItems.length} items for user ${user.name} (days=${days}, showAll=${showAll})`);

    res.json({
      user: user.name,
      isAdmin,
      days,
      history: historyItems
    });
  } catch (err) {
    console.error('[History] Error:', err.message);
    res.status(500).json({ error: 'Failed to fetch history', details: sanitizeError(err) });
  }
});

module.exports = router;
