const STORAGE_KEYS = {
  queue: 'playbackQueue',
  removed: 'removedEpisodes',
  history: 'playHistory',
};

export const QUEUE_STORAGE_KEY = STORAGE_KEYS.queue;
export const REMOVED_STORAGE_KEY = STORAGE_KEYS.removed;
export const HISTORY_STORAGE_KEY = STORAGE_KEYS.history;

/**
 * 待播放队列：存储为包含必要渲染字段的节目对象数组。
 */
export async function getQueue() {
  const stored = await chrome.storage.local.get({ [STORAGE_KEYS.queue]: [] });
  const list = Array.isArray(stored[STORAGE_KEYS.queue]) ? stored[STORAGE_KEYS.queue] : [];
  // 过滤非法项，仅保留具备 id 的对象
  const normalized = list
    .filter(item => item && typeof item === 'object' && ensureString(item.id))
    .map(item => normalizeEpisode(item));
  if (normalized.length !== list.length) {
    await chrome.storage.local.set({ [STORAGE_KEYS.queue]: normalized });
  }
  return normalized;
}

export async function setQueue(queue) {
  const list = Array.isArray(queue) ? queue.map(item => normalizeEpisode(item)).filter(Boolean) : [];
  await chrome.storage.local.set({ [STORAGE_KEYS.queue]: list });
  return list;
}

export async function addToQueueFront(episode) {
  const id = ensureString(episode?.id);
  if (!id) return [];
  const current = await getQueue();
  const filtered = current.filter(e => e.id !== id);
  const next = [normalizeEpisode(episode), ...filtered];
  await setQueue(next);
  return next;
}

export async function addToQueueNext(episode, { afterCurrent = true } = {}) {
  const id = ensureString(episode?.id);
  if (!id) return [];
  const current = await getQueue();
  const filtered = current.filter(e => e.id !== id);
  const insertIndex = afterCurrent ? Math.min(1, filtered.length) : 0;
  filtered.splice(insertIndex, 0, normalizeEpisode(episode));
  await setQueue(filtered);
  return filtered;
}

export async function removeFromQueueById(id) {
  const episodeId = ensureString(id);
  if (!episodeId) return [];
  const current = await getQueue();
  const next = current.filter(e => e.id !== episodeId);
  await setQueue(next);
  return next;
}

/**
 * 已移除节目：存储为字符串 ID 数组。
 */
export async function getRemovedEpisodeIds() {
  const stored = await chrome.storage.local.get({ [STORAGE_KEYS.removed]: [] });
  const arr = Array.isArray(stored[STORAGE_KEYS.removed]) ? stored[STORAGE_KEYS.removed] : [];
  const normalized = Array.from(new Set(arr.map(id => ensureString(id)).filter(Boolean)));
  if (normalized.length !== arr.length) {
    await chrome.storage.local.set({ [STORAGE_KEYS.removed]: normalized });
  }
  return normalized;
}

export async function addRemovedEpisodeId(id) {
  const episodeId = ensureString(id);
  if (!episodeId) return [];
  const list = await getRemovedEpisodeIds();
  if (!list.includes(episodeId)) {
    const next = [episodeId, ...list];
    await chrome.storage.local.set({ [STORAGE_KEYS.removed]: next });
    return next;
  }
  return list;
}

export async function removeRemovedEpisodeId(id) {
  const episodeId = ensureString(id);
  if (!episodeId) return [];
  const list = await getRemovedEpisodeIds();
  const next = list.filter(x => x !== episodeId);
  await chrome.storage.local.set({ [STORAGE_KEYS.removed]: next });
  return next;
}

/**
 * 播放历史：存储为 { episodeId, playedAt, lastPosition } 数组。
 */
export async function getPlayHistory() {
  const stored = await chrome.storage.local.get({ [STORAGE_KEYS.history]: [] });
  const list = Array.isArray(stored[STORAGE_KEYS.history]) ? stored[STORAGE_KEYS.history] : [];
  const normalized = list
    .map(item => normalizeHistoryItem(item))
    .filter(Boolean)
    .sort((a, b) => (b.playedAt || 0) - (a.playedAt || 0));
  if (normalized.length !== list.length) {
    await chrome.storage.local.set({ [STORAGE_KEYS.history]: normalized });
  }
  return normalized;
}

export async function addHistoryEntry(episodeOrId, { positionSec = 0 } = {}) {
  const episodeId = typeof episodeOrId === 'string' ? ensureString(episodeOrId) : ensureString(episodeOrId?.id);
  if (!episodeId) return [];
  const current = await getPlayHistory();
  const now = Date.now();
  const entry = {
    episodeId,
    lastPosition: Number(positionSec) || 0,
    playedAt: now,
  };
  const filtered = current.filter(e => e.episodeId !== episodeId);
  const next = [entry, ...filtered];
  await chrome.storage.local.set({ [STORAGE_KEYS.history]: next });
  return next;
}

export async function removeHistoryEntry(id) {
  const episodeId = ensureString(id);
  if (!episodeId) return [];
  const current = await getPlayHistory();
  const next = current.filter(entry => entry.episodeId !== episodeId);
  await chrome.storage.local.set({ [STORAGE_KEYS.history]: next });
  return next;
}

function normalizeEpisode(raw) {
  if (!raw || typeof raw !== 'object') return null;
  const id = ensureString(raw.id);
  if (!id) return null;
  let audioUrl = ensureString(raw.audioUrl || raw.audio?.url);
  const backupAudioUrls = collectBackupAudioUrls(raw);
  if (!audioUrl && backupAudioUrls.length) {
    audioUrl = backupAudioUrls[0];
  }
  return {
    id,
    episodeTitle: ensureString(raw.episodeTitle || raw.title || id),
    audioUrl,
    backupAudioUrls,
    cover: ensureString(raw.cover || raw.image || ''),
    publishedAt: raw.publishedAt || raw.publishAt || raw.updatedAt || raw.createdAt || null,
    duration: toNumberOrUndefined(
      raw.duration || raw.durationSec || raw.durationSeconds || raw.audio?.duration
    ),
    episodeLink: ensureString(raw.episodeLink || raw.link || ''),
    podcastTitle: ensureString(raw.podcastTitle || raw.podcast?.title || ''),
    podcastSourceRef: ensureString(raw.podcastSourceRef || raw.podcast?.sourceRef || ''),
    podcastLink: ensureString(raw.podcastLink || raw.podcast?.link || ''),
  };
}

function normalizeHistoryItem(raw) {
  if (!raw || typeof raw !== 'object') return null;
  const episodeId = ensureString(raw.episodeId);
  if (!episodeId) return null;
  const lastPosition = toNumberOrUndefined(raw.lastPosition) || 0;
  const playedAt = toNumberOrUndefined(raw.playedAt) || Date.now();
  return { episodeId, lastPosition, playedAt };
}

function ensureString(value) {
  if (typeof value === 'string') return value.trim();
  if (typeof value === 'number') return String(value);
  return '';
}

function toNumberOrUndefined(value) {
  if (value == null) return undefined;
  const num = Number(value);
  return Number.isFinite(num) ? num : undefined;
}

function collectBackupAudioUrls(raw) {
  const urls = [];
  const seen = new Set();
  const push = value => {
    const normalized = normalizeHttpUrl(value);
    if (!normalized || seen.has(normalized)) return;
    seen.add(normalized);
    urls.push(normalized);
  };

  const media = raw?.media || {};
  if (media.backupSource) {
    push(media.backupSource.url || media.backupSource.src || media.backupSource);
  }
  if (Array.isArray(media.backupSources)) {
    media.backupSources.forEach(item => {
      if (!item) return;
      if (typeof item === 'string') {
        push(item);
      } else {
        push(item.url || item.src);
      }
    });
  }
  if (Array.isArray(media.sources)) {
    media.sources.forEach(item => {
      if (!item) return;
      if (typeof item === 'string') {
        push(item);
      } else {
        push(item.url || item.src);
      }
    });
  }
  if (media.backupUrl) push(media.backupUrl);
  if (media.fallbackUrl) push(media.fallbackUrl);

  const extras = [
    raw?.backupAudioUrl,
    raw?.alternativeAudioUrl,
    raw?.fallbackAudioUrl,
  ];
  extras.forEach(push);

  if (Array.isArray(raw?.backupAudioUrls)) {
    raw.backupAudioUrls.forEach(push);
  }
  if (Array.isArray(raw?.audioAlternatives)) {
    raw.audioAlternatives.forEach(push);
  }
  if (Array.isArray(raw?.alternateAudioUrls)) {
    raw.alternateAudioUrls.forEach(push);
  }

  return urls;
}

function normalizeHttpUrl(value) {
  const str = ensureString(value);
  if (!str) return '';
  if (/^https?:\/\//i.test(str)) return str;
  if (str.startsWith('//')) return `https:${str}`;
  return '';
}
