import crypto from 'node:crypto';

function hashIp(ip) {
  return crypto.createHash('sha256').update(String(ip ?? 'unknown')).digest('hex').slice(0, 32);
}

function normalizeUtm(value, maxLen = 100) {
  return String(value ?? '')
    .trim()
    .slice(0, maxLen);
}

function normalizeEventType(value) {
  const type = String(value ?? '').trim();
  if (type === 'landing' || type === 'signup') return type;
  throw Object.assign(new Error('不支持的 attribution 事件类型'), { code: 'invalid_input' });
}

export const seoInternals = {
  normalizeUtm,
  normalizeEventType,
  buildPostPublicUrl,
};

export function buildPostPublicUrl(postId, siteBase = process.env.PLAZA_PUBLIC_BASE ?? 'https://plaza.tkmind.cn') {
  const base = String(siteBase).replace(/\/$/, '');
  return `${base}/plaza/p/${postId}`;
}

export function createPlazaSeoService(
  pool,
  {
    idFactory = () => crypto.randomUUID(),
    siteBase = process.env.PLAZA_PUBLIC_BASE ?? 'https://plaza.tkmind.cn',
    baiduToken = process.env.PLAZA_BAIDU_PUSH_TOKEN ?? '',
    baiduSite = process.env.PLAZA_BAIDU_SITE ?? 'plaza.tkmind.cn',
  } = {},
) {
  const listSitemapData = async ({ postLimit = 1000, userLimit = 500 } = {}) => {
    const [categoryRows] = await pool.query(
      `SELECT slug, name FROM plaza_categories WHERE is_active = 1 ORDER BY sort_order ASC`,
    );
    const [postRows] = await pool.query(
      `SELECT id, updated_at, published_at
       FROM plaza_posts
       WHERE status = 'published'
       ORDER BY published_at DESC
       LIMIT ?`,
      [Math.min(Math.max(Number(postLimit) || 1000, 1), 5000)],
    );
    const [userRows] = await pool.query(
      `SELECT u.slug, u.username, MAX(pp.published_at) AS last_post_at
       FROM h5_users u
       JOIN plaza_posts pp ON pp.user_id = u.id AND pp.status = 'published'
       GROUP BY u.id, u.slug, u.username
       ORDER BY last_post_at DESC
       LIMIT ?`,
      [Math.min(Math.max(Number(userLimit) || 500, 1), 2000)],
    );

    return {
      categories: categoryRows.map((row) => ({
        slug: row.slug,
        name: row.name,
      })),
      posts: postRows.map((row) => ({
        id: row.id,
        updated_at: new Date(Number(row.updated_at ?? row.published_at)).toISOString(),
        published_at: new Date(Number(row.published_at)).toISOString(),
      })),
      users: userRows.map((row) => ({
        slug: row.slug || row.username,
        last_post_at: row.last_post_at
          ? new Date(Number(row.last_post_at)).toISOString()
          : new Date().toISOString(),
      })),
    };
  };

  const recordAttribution = async (
    {
      event_type: eventTypeInput,
      utm_source: utmSource,
      utm_medium: utmMedium,
      utm_campaign: utmCampaign,
      ref_id: refId,
      user_id: userId = null,
    },
    ip = 'unknown',
  ) => {
    const eventType = normalizeEventType(eventTypeInput);
    const source = normalizeUtm(utmSource);
    if (!source) throw Object.assign(new Error('utm_source 不能为空'), { code: 'invalid_input' });

    const id = idFactory();
    const now = Date.now();
    await pool.query(
      `INSERT INTO plaza_attribution_events
       (id, event_type, utm_source, utm_medium, utm_campaign, ref_id, user_id, ip_hash, created_at)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        id,
        eventType,
        source,
        normalizeUtm(utmMedium),
        normalizeUtm(utmCampaign),
        normalizeUtm(refId, 200),
        userId,
        hashIp(ip),
        now,
      ],
    );
    return { id, event_type: eventType };
  };

  const pingBaidu = async (urls) => {
    const list = Array.isArray(urls) ? urls.filter(Boolean) : [urls].filter(Boolean);
    if (!baiduToken || list.length === 0) {
      return { pushed: false, reason: 'disabled_or_empty' };
    }
    const endpoint = `http://data.zz.baidu.com/urls?site=${encodeURIComponent(baiduSite)}&token=${encodeURIComponent(baiduToken)}`;
    const response = await fetch(endpoint, {
      method: 'POST',
      headers: { 'Content-Type': 'text/plain' },
      body: list.join('\n'),
    });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) {
      throw Object.assign(new Error('百度推送失败'), { code: 'baidu_push_failed', details: payload });
    }
    return { pushed: true, result: payload };
  };

  const notifyPostPublished = async (postId) => {
    const url = buildPostPublicUrl(postId, siteBase);
    try {
      return await pingBaidu([url]);
    } catch (error) {
      console.error('Plaza Baidu push failed:', error.message);
      return { pushed: false, reason: error.message };
    }
  };

  return {
    listSitemapData,
    recordAttribution,
    pingBaidu,
    notifyPostPublished,
  };
}
