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

const STORAGE_KEY = 'subscriptions';

/**
 * 读取订阅列表并返回标准化结构。
 */
export async function getSubscriptions() {
  const stored = await chrome.storage.sync.get({ [STORAGE_KEY]: [] });
  const rawList = Array.isArray(stored[STORAGE_KEY]) ? stored[STORAGE_KEY] : [];

  const { subscriptions, mutated } = normalizeSubscriptionList(rawList);
  if (mutated) {
    await chrome.storage.sync.set({ [STORAGE_KEY]: subscriptions });
  }

  return subscriptions;
}

/**
 * 新增订阅；若重复则抛出异常。
 */
export async function addSubscription({ sourceRef, source = SOURCE_XIAOYUZHOU, title }) {
  const normalizedSource = detectSource(sourceRef, source);
  const normalizedSourceRef = ensureId(sourceRef);
  const normalizedTitle = ensureOptionalString(title);

  if (!normalizedSourceRef) {
    throw createSubscriptionError('ERR_INVALID_SOURCE_REF', '订阅 ID 不能为空');
  }

  const subscriptions = await getSubscriptions();
  const exists = subscriptions.some(item => item.source === normalizedSource && item.sourceRef === normalizedSourceRef);
  if (exists) {
    throw createSubscriptionError('ERR_DUPLICATED_SUBSCRIPTION', '该订阅已存在');
  }

  const subscription = {
    source: normalizedSource,
    sourceRef: normalizedSourceRef,
    title: normalizedTitle || undefined,
    addedAt: Date.now(),
  };

  const next = [subscription, ...subscriptions];
  await chrome.storage.sync.set({ [STORAGE_KEY]: next });
  return subscription;
}

/**
 * 删除订阅项。
 */
export async function removeSubscription({ sourceRef, source = SOURCE_XIAOYUZHOU }) {
  const normalizedSource = detectSource(sourceRef, source);
  const normalizedSourceRef = ensureId(sourceRef);
  if (!normalizedSourceRef) {
    throw createSubscriptionError('ERR_INVALID_SOURCE_REF', '订阅 ID 不能为空');
  }

  const subscriptions = await getSubscriptions();
  const next = subscriptions.filter(item => !(item.source === normalizedSource && item.sourceRef === normalizedSourceRef));
  if (next.length === subscriptions.length) {
    throw createSubscriptionError('ERR_SUBSCRIPTION_NOT_FOUND', '订阅不存在或已删除');
  }

  await chrome.storage.sync.set({ [STORAGE_KEY]: next });
  // 取消订阅时同步清理对应的缓存（podcastCache 中的该播客条目）
  try {
    const stored = await chrome.storage.local.get({ podcastCache: {} });
    const cache = stored?.podcastCache && typeof stored.podcastCache === 'object' ? stored.podcastCache : {};
    const key = `${normalizedSource}:${normalizedSourceRef}`;
    if (cache[key]) {
      delete cache[key];
      await chrome.storage.local.set({ podcastCache: cache });
    }
  } catch (_) {
    // ignore storage cleanup errors
  }
  return next;
}

/**
 * 更新订阅属性，目前用于更新标题。
 */
export async function updateSubscription({ sourceRef, source = SOURCE_XIAOYUZHOU }, patch) {
  const normalizedSource = ensureSource(source);
  const normalizedSourceRef = ensureId(sourceRef);
  if (!normalizedSourceRef) {
    throw createSubscriptionError('ERR_INVALID_SOURCE_REF', '订阅 ID 不能为空');
  }

  const subscriptions = await getSubscriptions();
  let updatedSubscription = null;
  const next = subscriptions.map(item => {
    if (item.source === normalizedSource && item.sourceRef === normalizedSourceRef) {
      const nextItem = {
        ...item,
      };
      if (Object.prototype.hasOwnProperty.call(patch, 'title')) {
        const title = ensureOptionalString(patch.title);
        nextItem.title = title || undefined;
      }
      if (Object.prototype.hasOwnProperty.call(patch, 'source')) {
        nextItem.source = ensureSource(patch.source);
      }
      updatedSubscription = nextItem;
      return nextItem;
    }
    return item;
  });

  if (!updatedSubscription) {
    throw createSubscriptionError('ERR_SUBSCRIPTION_NOT_FOUND', '订阅不存在或已删除');
  }

  await chrome.storage.sync.set({ [STORAGE_KEY]: next });
  return updatedSubscription;
}

/**
 * 将任意输入列表转为标准订阅数组，返回是否发生了结构调整。
 */
function normalizeSubscriptionList(rawList) {
  const map = new Map();
  const subscriptions = [];
  let mutated = false;

  rawList.forEach(entry => {
    const normalized = normalizeSubscription(entry);
    if (!normalized) {
      mutated = true;
      return;
    }
    const key = `${normalized.source}::${normalized.sourceRef}`;
    if (map.has(key)) {
      mutated = true;
      return;
    }
    map.set(key, true);
    subscriptions.push(normalized);
  });

  subscriptions.sort((a, b) => (b.addedAt || 0) - (a.addedAt || 0));
  return { subscriptions, mutated };
}

function normalizeSubscription(entry) {
  if (typeof entry === 'string') {
    const sourceRef = ensureId(entry);
    if (!sourceRef) {
      return null;
    }
    return {
      source: detectSource(sourceRef, SOURCE_XIAOYUZHOU),
      sourceRef,
      addedAt: Date.now(),
    };
  }

  if (!entry || typeof entry !== 'object') {
    return null;
  }

  const sourceRef = ensureId(entry.sourceRef ?? entry.id);
  if (!sourceRef) {
    return null;
  }

  const source = detectSource(sourceRef, entry.source ?? entry.platform);
  const title = ensureOptionalString(entry.title ?? entry.name);
  const addedAt = ensureTimestamp(entry.addedAt ?? entry.createdAt);

  const normalized = {
    source,
    sourceRef,
  };

  if (title) {
    normalized.title = title;
  }
  normalized.addedAt = addedAt ?? Date.now();

  return normalized;
}

function ensureSource(source) {
  const value = ensureString(source) || SOURCE_XIAOYUZHOU;
  return value.toLowerCase();
}

function detectSource(sourceRef, source) {
  const ref = ensureString(sourceRef);
  const src = ensureString(source).toLowerCase();
  if (/^https?:\/\//i.test(ref)) {
    return 'rss';
  }
  return src || SOURCE_XIAOYUZHOU;
}

function ensureId(input) {
  return ensureString(input);
}

function ensureOptionalString(value) {
  const str = ensureString(value);
  return str || '';
}

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

function ensureTimestamp(value) {
  if (value == null) {
    return undefined;
  }
  const num = Number(value);
  if (Number.isFinite(num) && num > 0) {
    return num;
  }
  const parsed = Date.parse(value);
  return Number.isFinite(parsed) ? parsed : undefined;
}

function createSubscriptionError(code, message) {
  const error = new Error(message);
  error.code = code;
  return error;
}
