import fp from 'fastify-plugin';
import { fetchTweets, fetchAllTweets, extractTitle, extractYoutubeVideoIds, extractProfile } from './scraper.js';
import { fetchVideoInfo } from '../youtube/api.js';
import { formatDate, formatTime } from '../../utils/date.js';
import bots from '../../config/bots.js';

const X_CATEGORY_ID = 3;
const YOUTUBE_CATEGORY_ID = 2;
const PROFILE_CACHE_PREFIX = 'x_profile:';
const PROFILE_TTL = 604800; // 7일

async function xBotPlugin(fastify, opts) {
  /**
   * 관리 중인 YouTube 채널 ID 목록
   */
  function getManagedChannelIds() {
    return bots
      .filter(b => b.type === 'youtube')
      .map(b => b.channelId);
  }

  /**
   * X 프로필 저장 (DB + Redis 캐시)
   */
  async function saveProfile(username, profile) {
    if (!profile.displayName && !profile.avatarUrl) return;

    // DB에 저장 (upsert)
    await fastify.db.query(`
      INSERT INTO x_profiles (username, display_name, avatar_url)
      VALUES (?, ?, ?)
      ON DUPLICATE KEY UPDATE
        display_name = VALUES(display_name),
        avatar_url = VALUES(avatar_url),
        updated_at = CURRENT_TIMESTAMP
    `, [username, profile.displayName, profile.avatarUrl]);

    // Redis 캐시에도 저장
    const data = {
      username,
      displayName: profile.displayName,
      avatarUrl: profile.avatarUrl,
      updatedAt: new Date().toISOString(),
    };
    await fastify.redis.setex(
      `${PROFILE_CACHE_PREFIX}${username}`,
      PROFILE_TTL,
      JSON.stringify(data)
    );
  }

  /**
   * 트윗을 DB에 저장
   */
  async function saveTweet(tweet) {
    // 중복 체크 (post_id로)
    const [existing] = await fastify.db.query(
      'SELECT id FROM schedule_x WHERE post_id = ?',
      [tweet.id]
    );
    if (existing.length > 0) {
      return null;
    }

    const date = formatDate(tweet.time);
    const time = formatTime(tweet.time);
    const title = extractTitle(tweet.text);

    // schedules 테이블에 저장
    const [result] = await fastify.db.query(
      'INSERT INTO schedules (category_id, title, date, time) VALUES (?, ?, ?, ?)',
      [X_CATEGORY_ID, title, date, time]
    );
    const scheduleId = result.insertId;

    // schedule_x 테이블에 저장
    await fastify.db.query(
      'INSERT INTO schedule_x (schedule_id, post_id, content, image_urls) VALUES (?, ?, ?, ?)',
      [
        scheduleId,
        tweet.id,
        tweet.text,
        tweet.imageUrls.length > 0 ? JSON.stringify(tweet.imageUrls) : null,
      ]
    );

    return scheduleId;
  }

  /**
   * YouTube 영상을 DB에 저장 (트윗에서 감지된 링크)
   */
  async function saveYoutubeFromTweet(video) {
    // 중복 체크
    const [existing] = await fastify.db.query(
      'SELECT id FROM schedule_youtube WHERE video_id = ?',
      [video.videoId]
    );
    if (existing.length > 0) {
      return null;
    }

    // schedules 테이블에 저장
    const [result] = await fastify.db.query(
      'INSERT INTO schedules (category_id, title, date, time) VALUES (?, ?, ?, ?)',
      [YOUTUBE_CATEGORY_ID, video.title, video.date, video.time]
    );
    const scheduleId = result.insertId;

    // schedule_youtube 테이블에 저장
    await fastify.db.query(
      'INSERT INTO schedule_youtube (schedule_id, video_id, video_type, channel_id, channel_name) VALUES (?, ?, ?, ?, ?)',
      [scheduleId, video.videoId, video.videoType, video.channelId, video.channelTitle]
    );

    return scheduleId;
  }

  /**
   * 트윗에서 YouTube 링크 처리
   */
  async function processYoutubeLinks(tweet) {
    const videoIds = extractYoutubeVideoIds(tweet.text);
    if (videoIds.length === 0) return 0;

    const managedChannels = getManagedChannelIds();
    let addedCount = 0;

    for (const videoId of videoIds) {
      try {
        const video = await fetchVideoInfo(videoId);
        if (!video) continue;

        // 관리 중인 채널이면 스킵
        if (managedChannels.includes(video.channelId)) continue;

        const saved = await saveYoutubeFromTweet(video);
        if (saved) addedCount++;
      } catch (err) {
        fastify.log.error(`YouTube 영상 처리 오류 (${videoId}): ${err.message}`);
      }
    }

    return addedCount;
  }

  /**
   * 최근 트윗 동기화 (정기 실행)
   */
  async function syncNewTweets(bot) {
    const { tweets, profile } = await fetchTweets(bot.nitterUrl, bot.username);

    // 프로필 저장 (DB + 캐시)
    await saveProfile(bot.username, profile);

    let addedCount = 0;
    let ytAddedCount = 0;

    for (const tweet of tweets) {
      const scheduleId = await saveTweet(tweet);
      if (scheduleId) {
        addedCount++;
        // YouTube 링크 처리
        ytAddedCount += await processYoutubeLinks(tweet);
      }
    }

    return { addedCount: addedCount + ytAddedCount, tweetCount: addedCount, ytCount: ytAddedCount };
  }

  /**
   * 전체 트윗 동기화 (초기화)
   */
  async function syncAllTweets(bot) {
    const tweets = await fetchAllTweets(bot.nitterUrl, bot.username, fastify.log);

    let addedCount = 0;
    let ytAddedCount = 0;

    for (const tweet of tweets) {
      const scheduleId = await saveTweet(tweet);
      if (scheduleId) {
        addedCount++;
        ytAddedCount += await processYoutubeLinks(tweet);
      }
    }

    return { addedCount: addedCount + ytAddedCount, tweetCount: addedCount, ytCount: ytAddedCount };
  }

  /**
   * X 프로필 조회 (Redis 캐시 → DB)
   */
  async function getProfile(username) {
    // Redis 캐시 확인
    const cached = await fastify.redis.get(`${PROFILE_CACHE_PREFIX}${username}`);
    if (cached) {
      return JSON.parse(cached);
    }

    // DB에서 조회
    const [rows] = await fastify.db.query(
      'SELECT username, display_name, avatar_url, updated_at FROM x_profiles WHERE username = ?',
      [username]
    );

    if (rows.length > 0) {
      const row = rows[0];
      const data = {
        username: row.username,
        displayName: row.display_name,
        avatarUrl: row.avatar_url,
        updatedAt: row.updated_at?.toISOString(),
      };
      // Redis 캐시에 저장
      await fastify.redis.setex(
        `${PROFILE_CACHE_PREFIX}${username}`,
        PROFILE_TTL,
        JSON.stringify(data)
      );
      return data;
    }

    return null;
  }

  fastify.decorate('xBot', {
    syncNewTweets,
    syncAllTweets,
    getProfile,
  });
}

export default fp(xBotPlugin, {
  name: 'xBot',
  dependencies: ['db', 'redis'],
});
