import { SOURCE_XIAOYUZHOU } from './constants.js';

/**
 * 将小宇宙合集页面的原始数据转换成统一的数据模型。
 */
export function transformCollection(payload, { sourceRef }) {
  const pageProps = payload?.pageProps ?? {};
  const collectionRaw = pageProps?.collection ?? {};
  const collectionId = ensureString(collectionRaw.id) || ensureString(sourceRef);

  const entries = gatherCollectionEntries(collectionRaw, pageProps);
  const podcasts = entries
    .map(entry => toPodcastModel(entry))
    .filter(Boolean);

  return {
    collection: {
      id: collectionId,
      title: ensureString(collectionRaw.title),
      description: sanitizeText(collectionRaw.description ?? ''),
      totalPodcasts: podcasts.length,
      source: SOURCE_XIAOYUZHOU,
      sourceRef: collectionId || ensureString(sourceRef),
    },
    podcasts,
  };
}

/**
 * 将小宇宙播客页面的原始数据转换成统一的数据模型。
 */
export function transformPodcast(payload, { sourceRef }) {
  const pageProps = payload?.pageProps ?? {};
  const podcastRaw =
    pageProps?.podcast ??
    pageProps?.podcastDetail ??
    pageProps?.podcastInfo ??
    {};

  const resolvedSourceRef = ensureString(sourceRef) || extractPodcastSourceRef(podcastRaw);
  if (!resolvedSourceRef) {
    throw createTransformError('ERR_PODCAST_ID', 'Unable to determine podcast identifier');
  }

  const podcast = toPodcastModel(podcastRaw, resolvedSourceRef);
  const podcastId = podcast?.id ?? createPodcastId(resolvedSourceRef);
  const episodesRaw = gatherPodcastEpisodes(pageProps, podcastRaw);
  const podcastCover = podcast?.cover || selectImage(podcastRaw);
  const mappedEpisodes = episodesRaw
    .map(raw => toEpisodeModel(raw, { podcastId, podcastCover }))
    .filter(Boolean);

  const episodes = sortEpisodesByPublishedAt(mappedEpisodes);

  return {
    podcast,
    episodes,
  };
}

/**
 * 将小宇宙节目页面的原始数据转换成统一的数据模型。
 */
export function transformEpisode(payload, { sourceRef }) {
  const pageProps = payload?.pageProps ?? {};
  const episodeRaw = pageProps?.episode ?? {};
  const episodeSourceRef = extractEpisodeSourceRef(episodeRaw) || ensureString(sourceRef);
  if (!episodeSourceRef) {
    throw createTransformError('ERR_EPISODE_ID', 'Unable to determine episode identifier');
  }

  const podcastRaw =
    episodeRaw?.podcast ??
    pageProps?.podcast ??
    pageProps?.podcastInfo ??
    {};
  const podcastSourceRef =
    extractPodcastSourceRef(podcastRaw) ||
    ensureString(episodeRaw?.podcastId) ||
    '';

  const podcast =
    podcastSourceRef && Object.keys(podcastRaw || {}).length
      ? toPodcastModel(podcastRaw, podcastSourceRef)
      : undefined;

  const podcastId = podcast?.id ?? createPodcastId(podcastSourceRef || `unknown:${episodeSourceRef}`);
  const podcastCover = podcast?.cover || selectImage(podcastRaw);

  const episode = toEpisodeModel(episodeRaw, { podcastId, podcastCover });

  return {
    episode,
    podcast,
  };
}

/**
 * 汇总合集页面上的播客条目，聚合到单一数组中。
 */
function gatherCollectionEntries(collectionRaw, pageProps) {
  const entries = [];

  if (Array.isArray(collectionRaw?.target)) {
    entries.push(...collectionRaw.target);
  }
  if (Array.isArray(collectionRaw?.podcasts)) {
    entries.push(...collectionRaw.podcasts);
  }
  if (Array.isArray(pageProps?.collectionItems)) {
    pageProps.collectionItems.forEach(item => {
      if (item?.podcast) entries.push(item.podcast);
      if (item?.entity) entries.push(item.entity);
    });
  }

  return entries;
}

/**
 * 汇总播客页面上的节目条目，并按 sourceRef 去重。
 */
function gatherPodcastEpisodes(pageProps, podcastRaw) {
  const candidates = [
    toArray(pageProps?.episodes),
    toArray(pageProps?.podcastEpisodes),
    toArray(pageProps?.episodeList),
    toArray(podcastRaw?.episodes),
  ];

  const map = new Map();
  candidates.forEach(list => {
    list.forEach(item => {
      const raw = item?.episode ?? item;
      const sourceRef = extractEpisodeSourceRef(raw);
      if (sourceRef && !map.has(sourceRef)) {
        map.set(sourceRef, raw);
      }
    });
  });

  return Array.from(map.values());
}

/**
 * 将原始播客对象映射为统一的 Podcast 模型。
 */
function toPodcastModel(raw, forcedSourceRef) {
  if (!raw || typeof raw !== 'object') {
    return null;
  }

  const sourceRef = forcedSourceRef || extractPodcastSourceRef(raw);
  if (!sourceRef) {
    return null;
  }

  const podcastId = createPodcastId(sourceRef);
  const title = ensureString(raw.title ?? raw.name ?? '');
  const description = sanitizeText(raw.description ?? raw.brief ?? '');
  const author = resolveAuthor(raw);
  const link = ensureString(raw.url ?? raw.shareUrl) || `https://www.xiaoyuzhoufm.com/podcast/${sourceRef}`;
  const totalEpisodes = numberOrUndefined(
    raw.episodeCount ?? raw.programCount ?? raw.totalEpisodes
  );
  const subscriberCount = numberOrUndefined(
    raw.subscriptionCount ?? raw.subscriberCount ?? raw.followersCount
  );
  const lastUpdatedAt = normalizeDate(
    raw.latestEpisodePubDate ??
      raw.lastEpisodePubDate ??
      raw.updatedAt ??
      raw.publishAt ??
      raw.createdAt
  );

  const tags =
    Array.isArray(raw.topicLabels) && raw.topicLabels.length
      ? raw.topicLabels.map(label => ensureString(label))
      : undefined;

  const podcast = {
    id: podcastId,
    title: title || sourceRef,
    description: description || undefined,
    author: author || undefined,
    cover: selectImage(raw) || undefined,
    link,
    source: SOURCE_XIAOYUZHOU,
    sourceRef,
    lastUpdatedAt,
    totalEpisodes,
    subscriberCount,
    tags,
  };

  const extra = collectPodcastExtra(raw);
  if (extra) {
    podcast.extra = extra;
  }

  return podcast;
}

/**
 * 将原始节目对象映射为统一的 Episode 模型。
 */
function toEpisodeModel(raw, { podcastId, podcastCover }) {
  if (!raw || typeof raw !== 'object') {
    return null;
  }
  const sourceRef = extractEpisodeSourceRef(raw);
  if (!sourceRef) {
    return null;
  }

  const audioUrl =
    ensureString(raw.audioUrl) ||
    ensureString(raw.audio?.url) ||
    ensureString(raw.enclosure?.url) ||
    ensureString(raw.enclosures?.[0]?.url) ||
    ensureString(raw.media?.url);
  if (!audioUrl) {
    return null;
  }

  const episodeId = createEpisodeId(sourceRef);
  const title = ensureString(raw.title ?? raw.name ?? '');
  const description = sanitizeText(raw.description ?? raw.brief ?? '');
  const cover = selectImage(raw) || podcastCover || undefined;
  const duration = normalizeDuration(
    raw.duration ??
      raw.durationSec ??
      raw.durationSeconds ??
      raw.audio?.duration ??
      raw.durationMs ??
      raw.audio?.durationMs
  );
  const publishedAt = normalizeDate(
    raw.publishedAt ??
      raw.publishAt ??
      raw.updatedAt ??
      raw.createdAt ??
      raw.pubDate
  );

  const episode = {
    id: episodeId,
    podcastId,
    title: title || sourceRef,
    episodeTitle: title || sourceRef,  // 统一使用 episodeTitle 字段
    description: description || undefined,
    episodeDescription: description || undefined,  // 统一使用 episodeDescription 字段
    audioUrl,
    cover,
    duration,
    publishedAt,
    link: ensureString(raw.url ?? raw.shareUrl) || undefined,
    episodeLink: ensureString(raw.url ?? raw.shareUrl) || undefined,  // 统一使用 episodeLink 字段
    source: SOURCE_XIAOYUZHOU,
    sourceRef,
  };

  const extra = collectEpisodeExtra(raw);
  if (extra) {
    episode.extra = extra;
  }

  if (typeof raw.isExplicit === 'boolean') {
    episode.explicit = raw.isExplicit;
  }

  return episode;
}

/**
 * 从原始播客对象中提取 sourceRef。
 */
function extractPodcastSourceRef(raw) {
  if (!raw || typeof raw !== 'object') {
    return '';
  }
  return (
    ensureString(raw.pid) ||
    ensureString(raw.id) ||
    ensureString(raw.podcastId) ||
    ensureString(raw.sourceRef)
  );
}

/**
 * 从原始节目对象中提取 sourceRef。
 */
function extractEpisodeSourceRef(raw) {
  if (!raw || typeof raw !== 'object') {
    return '';
  }
  return (
    ensureString(raw.eid) ||
    ensureString(raw.id) ||
    ensureString(raw.episodeId) ||
    ensureString(raw.sourceRef) ||
    ensureString(raw.slug)
  );
}

/**
 * 收集播客模型额外字段，便于前端展示。
 */
function collectPodcastExtra(raw) {
  const extra = {};
  if (raw?.color?.original) {
    extra.brandColor = raw.color.original;
  }
  if (raw?.payType) {
    extra.payType = raw.payType;
  }
  if (raw?.syncMode) {
    extra.syncMode = raw.syncMode;
  }
  if (raw?.permissions) {
    extra.permissions = raw.permissions;
  }
  return Object.keys(extra).length ? extra : undefined;
}

/**
 * 收集节目模型额外字段，便于前端展示。
 */
function collectEpisodeExtra(raw) {
  const extra = {};
  if (raw?.audio?.duration) {
    extra.audioDuration = raw.audio.duration;
  }
  if (raw?.playCount != null) {
    extra.playCount = raw.playCount;
  }
  return Object.keys(extra).length ? extra : undefined;
}

/**
 * 解析播客的作者信息，组合成字符串。
 */
function resolveAuthor(raw) {
  const authors = [];
  if (typeof raw?.author === 'string' && raw.author.trim()) {
    authors.push(raw.author.trim());
  }
  if (raw?.owner?.nickname) {
    authors.push(String(raw.owner.nickname));
  }
  if (raw?.user?.nickname) {
    authors.push(String(raw.user.nickname));
  }
  if (Array.isArray(raw?.podcasters)) {
    raw.podcasters.forEach(entry => {
      const name = ensureString(entry?.nickname ?? entry?.name ?? entry?.username);
      if (name) {
        authors.push(name);
      }
    });
  }
  return Array.from(new Set(authors)).join(' / ');
}

/**
 * 将输入值统一转换为数组。
 */
function toArray(value) {
  if (!value) {
    return [];
  }
  return Array.isArray(value) ? value : [value];
}

/**
 * 将输入值规整为字符串。
 */
function ensureString(value) {
  if (typeof value === 'string') {
    return value.trim();
  }
  if (typeof value === 'number') {
    return String(value);
  }
  return '';
}

/**
 * 清洗文本并去除首尾空白。
 */
function sanitizeText(value) {
  if (typeof value !== 'string') {
    return '';
  }
  return value.trim();
}

/**
 * 将可选的数字字段转换为数字或 undefined。
 */
function numberOrUndefined(value) {
  if (value == null) {
    return undefined;
  }
  const num = Number(value);
  if (Number.isNaN(num)) {
    return undefined;
  }
  return num;
}

/**
 * 将时长字段统一换算为秒数。
 */
function normalizeDuration(value) {
  if (value == null) {
    return undefined;
  }
  const num = Number(value);
  if (!Number.isFinite(num) || num <= 0) {
    return undefined;
  }
  if (num > 10000) {
    return Math.round(num / 1000);
  }
  return Math.round(num);
}

/**
 * 将日期字段转换为 ISO 字符串。
 */
function normalizeDate(value) {
  if (!value) {
    return undefined;
  }
  if (typeof value === 'number') {
    return new Date(value).toISOString();
  }
  const timestamp = Date.parse(value);
  if (!Number.isNaN(timestamp)) {
    return new Date(timestamp).toISOString();
  }
  try {
    const parsed = new Date(value);
    if (!Number.isNaN(parsed.getTime())) {
      return parsed.toISOString();
    }
  } catch {
    // ignore
  }
  return undefined;
}

/**
 * 从多种图片字段中选取首个可用的封面 URL。
 */
function selectImage(raw) {
  if (!raw || typeof raw !== 'object') {
    return '';
  }
  const candidates = [
    raw?.image?.picUrl,
    raw?.image?.url,
    raw?.image?.cover,
    raw?.cover,
    raw?.poster,
    raw?.logo,
    raw?.icon,
    raw?.shareImage?.picUrl,
  ];
  for (const candidate of candidates) {
    const value = ensureString(candidate);
    if (value) {
      return value;
    }
  }
  return '';
}

/**
 * 生成统一的 Podcast ID。
 */
function createPodcastId(sourceRef) {
  return `podcast:${SOURCE_XIAOYUZHOU}:${sourceRef}`;
}

/**
 * 生成统一的 Episode ID。
 */
function createEpisodeId(sourceRef) {
  return `episode:${SOURCE_XIAOYUZHOU}:${sourceRef}`;
}

/**
 * 构造带错误码的转换错误对象。
 */
function createTransformError(code, message) {
  const error = new Error(message);
  error.code = code;
  return error;
}

/**
 * 按发布时间对节目列表进行降序排序。
 */
function sortEpisodesByPublishedAt(episodes) {
  if (!Array.isArray(episodes) || episodes.length <= 1) {
    return episodes || [];
  }
  return [...episodes].sort((a, b) => {
    const aTime = toTimestamp(a?.publishedAt);
    const bTime = toTimestamp(b?.publishedAt);
    return bTime - aTime;
  });
}

/**
 * 将 ISO 或日期字符串转换为时间戳，便于排序。
 */
function toTimestamp(value) {
  if (!value) {
    return 0;
  }
  const time = Date.parse(value);
  if (!Number.isNaN(time)) {
    return time;
  }
  const fallback = new Date(value).getTime();
  return Number.isNaN(fallback) ? 0 : fallback;
}
