/**
 * posimai-tech-events — server.js に追加するエンドポイント
 *
 * 使い方:
 *   このファイルの内容を server.js の既存ルートの末尾あたりにコピーする。
 *   Doorkeeper (JSON API) + connpass Atom RSS を取得して正規化して返す。
 *   追加 npm パッケージは不要（Node.js 18+ 組み込みの fetch を使用）。
 *
 * デプロイ:
 *   docker cp server.js posimai_api:/app/server.js && docker restart posimai_api
 */

// ─── /events/rss GET ──────────────────────────────────────────────────────────
app.get('/events/rss', async (req, res) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    try {
        const [doorkeeper, connpassEvents] = await Promise.allSettled([
            fetchDoorkeeper(),
            fetchConnpassRss(),
        ]);

        const events = [
            ...(doorkeeper.status === 'fulfilled' ? doorkeeper.value : []),
            ...(connpassEvents.status === 'fulfilled' ? connpassEvents.value : []),
        ];

        // URLで重複排除
        const seen = new Set();
        const unique = events.filter(ev => {
            if (seen.has(ev.url)) return false;
            seen.add(ev.url);
            return true;
        });

        // 開始日時順にソート
        unique.sort((a, b) => (a.startDate + a.startTime).localeCompare(b.startDate + b.startTime));

        res.json({ events: unique, fetched_at: new Date().toISOString() });
    } catch (err) {
        console.error('[events/rss]', err);
        res.status(500).json({ events: [], error: err.message });
    }
});

// ─── Doorkeeper JSON API（認証不要・CORS 問題なし） ─────────────────────────
async function fetchDoorkeeper() {
    const url = 'https://api.doorkeeper.jp/events?locale=ja&per_page=50&sort=starts_at';
    const res = await fetch(url, {
        headers: { 'Accept': 'application/json', 'User-Agent': 'Posimai/1.0' },
        signal: AbortSignal.timeout(8000),
    });
    if (!res.ok) throw new Error(`Doorkeeper ${res.status}`);
    const data = await res.json();

    return data.map((item, i) => {
        const ev = item.event;
        const start = new Date(ev.starts_at);
        const end = new Date(ev.ends_at || ev.starts_at);
        return {
            id: `doorkeeper-${ev.id}`,
            title: ev.title || '',
            url: ev.url || '',
            location: ev.venue_name || (ev.address ? ev.address.split(',')[0] : 'オンライン'),
            address: ev.address || '',
            startDate: toDateStr(start),
            endDate: toDateStr(end),
            startTime: toTimeStr(start),
            endTime: toTimeStr(end),
            category: 'IT イベント',
            description: stripHtml(ev.description || '').slice(0, 300),
            source: ev.group || 'Doorkeeper',
            isFree: false,
            interestTags: guessInterestTags(ev.title + ' ' + (ev.description || '')),
            audienceTags: guessAudienceTags(ev.title + ' ' + (ev.description || '')),
        };
    });
}

// ─── connpass Atom RSS（XMLをregexでパース） ──────────────────────────────────
async function fetchConnpassRss() {
    const url = 'https://connpass.com/explore/ja.atom';
    const res = await fetch(url, {
        headers: { 'Accept': 'application/atom+xml', 'User-Agent': 'Posimai/1.0' },
        signal: AbortSignal.timeout(8000),
    });
    if (!res.ok) throw new Error(`connpass RSS ${res.status}`);
    const xml = await res.text();

    const entries = [...xml.matchAll(/<entry>([\s\S]*?)<\/entry>/g)];
    return entries.map((match, i) => {
        const c = match[1];
        const title = extractXml(c, 'title');
        const url = /<link[^>]+href="([^"]+)"/.exec(c)?.[1] || '';
        const updated = extractXml(c, 'updated');
        const summary = extractXml(c, 'summary');
        const author = extractXml(c, 'name');

        const dt = updated ? new Date(updated) : new Date();
        return {
            id: `connpass-${i}-${toDateStr(dt)}`,
            title,
            url,
            location: 'connpass',
            address: '',
            startDate: toDateStr(dt),
            endDate: toDateStr(dt),
            startTime: toTimeStr(dt),
            endTime: toTimeStr(dt),
            category: 'IT イベント',
            description: summary.slice(0, 300),
            source: author || 'connpass',
            isFree: false,
            interestTags: guessInterestTags(title + ' ' + summary),
            audienceTags: guessAudienceTags(title + ' ' + summary),
        };
    });
}

// ─── ユーティリティ ────────────────────────────────────────────────────────────
function extractXml(xml, tag) {
    const m = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`).exec(xml);
    if (!m) return '';
    return m[1].replace(/<!\[CDATA\[|\]\]>/g, '')
               .replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
               .replace(/&quot;/g, '"').replace(/&#39;/g, "'").trim();
}

function stripHtml(html) {
    return html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
}

function toDateStr(dt) {
    return dt.toISOString().slice(0, 10);
}

function toTimeStr(dt) {
    // JST (+9h)
    const jst = new Date(dt.getTime() + 9 * 3600 * 1000);
    return jst.toISOString().slice(11, 16);
}

function guessInterestTags(text) {
    const tags = [];
    if (/React|Vue|TypeScript|フロントエンド|Next\.js|Svelte/i.test(text)) tags.push('frontend');
    if (/Go|Rust|Ruby|Python|PHP|バックエンド|API/i.test(text)) tags.push('backend');
    if (/デザイン|UX|Figma|UI/i.test(text)) tags.push('design');
    if (/AI|機械学習|LLM|GPT|Claude|Gemini/i.test(text)) tags.push('ai');
    if (/インフラ|AWS|GCP|Azure|クラウド|Docker|Kubernetes/i.test(text)) tags.push('infra');
    if (/iOS|Android|Flutter|React Native|モバイル/i.test(text)) tags.push('mobile');
    if (/データ|分析|ML|データサイエンス/i.test(text)) tags.push('data');
    if (/PM|プロダクト|プロダクトマネジメント/i.test(text)) tags.push('pm');
    if (/初心者|入門|ビギナー/i.test(text)) tags.push('beginner');
    return tags;
}

function guessAudienceTags(text) {
    const tags = [];
    if (/交流|ミートアップ|meetup/i.test(text)) tags.push('meetup');
    if (/もくもく/i.test(text)) tags.push('mokumoku');
    if (/セミナー|勉強会|study/i.test(text)) tags.push('seminar');
    if (/ハンズオン|hands.?on/i.test(text)) tags.push('handson');
    return tags;
}
