import { fetchSingleTweet, extractTitle } from '../../services/x/scraper.js';
import { addOrUpdateSchedule, syncScheduleById } from '../../services/meilisearch/index.js';
import { formatDate, formatTime } from '../../utils/date.js';
import config, { CATEGORY_IDS } from '../../config/index.js';
import {
  errorResponse,
  xPostInfoQuery,
  xScheduleCreate,
} from '../../schemas/index.js';
import { badRequest, conflict, serverError } from '../../utils/error.js';
import { logActivity } from '../../utils/log.js';

const X_CATEGORY_ID = CATEGORY_IDS.X;
const NITTER_URL = config.nitter?.url || process.env.NITTER_URL || 'http://nitter:8080';
const DEFAULT_USERNAME = config.x.defaultUsername;

/**
 * X(Twitter) 관련 관리자 라우트
 */
export default async function xRoutes(fastify) {
  const { db, meilisearch } = fastify;

  /**
   * GET /api/admin/x/post-info
   * X 게시글 정보 조회
   */
  fastify.get('/post-info', {
    schema: {
      tags: ['admin/x'],
      summary: 'X 게시글 정보 조회',
      description: 'X(Twitter) 게시글 ID로 정보를 조회합니다.',
      security: [{ bearerAuth: [] }],
      querystring: xPostInfoQuery,
      response: {
        200: {
          type: 'object',
          properties: {
            postId: { type: 'string' },
            username: { type: 'string' },
            text: { type: 'string' },
            title: { type: 'string' },
            imageUrls: { type: 'array', items: { type: 'string' } },
            date: { type: 'string' },
            time: { type: 'string' },
            postUrl: { type: 'string' },
            profile: {
              type: 'object',
              properties: {
                username: { type: 'string' },
                displayName: { type: 'string' },
                avatarUrl: { type: 'string' },
              },
            },
          },
        },
        400: errorResponse,
        500: errorResponse,
      },
    },
    preHandler: [fastify.authenticate],
  }, async (request, reply) => {
    const { postId, username = DEFAULT_USERNAME } = request.query;

    // 게시글 ID 유효성 검사
    if (!/^\d+$/.test(postId)) {
      return badRequest(reply, '유효하지 않은 게시글 ID입니다.');
    }

    try {
      const tweet = await fetchSingleTweet(NITTER_URL, username, postId);

      return {
        postId: tweet.id,
        username,
        text: tweet.text,
        title: extractTitle(tweet.text),
        imageUrls: tweet.imageUrls,
        date: tweet.time ? formatDate(tweet.time) : null,
        time: tweet.time ? formatTime(tweet.time) : null,
        postUrl: tweet.url,
        profile: tweet.profile,
      };
    } catch (err) {
      fastify.log.error(`X 게시글 조회 오류: ${err.message}`);
      return serverError(reply, err.message);
    }
  });

  /**
   * POST /api/admin/x/schedule
   * X 일정 저장
   */
  fastify.post('/schedule', {
    schema: {
      tags: ['admin/x'],
      summary: 'X 일정 저장',
      description: 'X(Twitter) 게시글을 일정으로 등록합니다.',
      security: [{ bearerAuth: [] }],
      body: xScheduleCreate,
      response: {
        200: {
          type: 'object',
          properties: {
            success: { type: 'boolean' },
            scheduleId: { type: 'integer' },
          },
        },
        409: errorResponse,
        500: errorResponse,
      },
    },
    preHandler: [fastify.authenticate],
  }, async (request, reply) => {
    const { postId, title, content, imageUrls, date, time } = request.body;

    try {
      // 중복 체크
      const [existing] = await db.query(
        'SELECT id FROM schedule_x WHERE post_id = ?',
        [postId]
      );
      if (existing.length > 0) {
        return conflict(reply, '이미 등록된 게시글입니다.');
      }

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

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

      // Meilisearch 동기화
      const [categoryRows] = await db.query(
        'SELECT name, color FROM schedule_categories WHERE id = ?',
        [X_CATEGORY_ID]
      );
      const category = categoryRows[0] || {};

      await addOrUpdateSchedule(meilisearch, {
        id: scheduleId,
        title,
        date,
        time: time || '',
        category_id: X_CATEGORY_ID,
        category_name: category.name || '',
        category_color: category.color || '',
        source_name: '',
      });

      logActivity(db, { actor: 'admin', action: 'create', category: 'schedule', targetType: 'x_schedule', targetId: scheduleId, summary: `X 일정 생성: ${title}` });
      return { success: true, scheduleId };
    } catch (err) {
      fastify.log.error(`X 일정 저장 오류: ${err.message}`);
      return serverError(reply, err.message);
    }
  });

  /**
   * POST /api/admin/x/refetch-retweets
   * 리트윗 데이터 재수집 (잘못된 content/image_urls 수정)
   */
  fastify.post('/refetch-retweets', {
    schema: {
      tags: ['admin/x'],
      summary: '리트윗 데이터 재수집',
      description: '잘못 저장된 리트윗 일정을 Nitter에서 다시 가져와 수정합니다.',
      security: [{ bearerAuth: [] }],
      body: {
        type: 'object',
        properties: {
          scheduleIds: {
            type: 'array',
            items: { type: 'integer' },
            description: '재수집할 일정 ID 목록 (비어있으면 전체 리트윗 대상)',
          },
        },
      },
    },
    preHandler: [fastify.authenticate],
  }, async (request, reply) => {
    try {
      let rows;
      const { scheduleIds } = request.body || {};

      if (scheduleIds && scheduleIds.length > 0) {
        // 특정 일정만
        [rows] = await db.query(
          `SELECT sx.schedule_id, sx.post_id, sx.username, sx.content
           FROM schedule_x sx
           WHERE sx.schedule_id IN (?)`,
          [scheduleIds]
        );
      } else {
        // content가 "RT @"로 시작하거나, image_urls가 NULL이면서 nitter 링크가 있는 일정
        [rows] = await db.query(
          `SELECT sx.schedule_id, sx.post_id, sx.username, sx.content
           FROM schedule_x sx
           WHERE sx.content LIKE 'RT @%'
              OR (sx.content LIKE '%nitter%t.co%')
              OR (sx.image_urls IS NULL AND sx.content LIKE 'RT @%')`
        );
      }

      if (rows.length === 0) {
        return { success: true, message: '재수집 대상이 없습니다.', updated: 0 };
      }

      let updated = 0;
      const errors = [];

      for (const row of rows) {
        try {
          // content에서 원본 작성자 추출 (RT @username: 형식)
          let fetchUsername = row.username || DEFAULT_USERNAME;
          const rtMatch = row.content?.match(/^RT @(\w+):/);
          if (rtMatch) {
            fetchUsername = rtMatch[1];
          }

          // 원본 작성자의 개별 트윗 페이지에서 가져오기
          const tweet = await fetchSingleTweet(NITTER_URL, fetchUsername, row.post_id);

          // fetchSingleTweet이 RT @ 형식을 반환하면 RT 프리픽스 제거
          let newContent = tweet.text;
          const rtPrefixMatch = newContent.match(/^RT @\w+:\s*/);
          if (rtPrefixMatch) {
            newContent = newContent.slice(rtPrefixMatch[0].length);
          }
          // 끝의 … 제거
          newContent = newContent.replace(/…$/, '').trim();

          const newTitle = extractTitle(newContent);
          const newImageUrls = tweet.imageUrls.length > 0 ? JSON.stringify(tweet.imageUrls) : null;

          // schedules 테이블 업데이트
          await db.query(
            'UPDATE schedules SET title = ? WHERE id = ?',
            [newTitle, row.schedule_id]
          );

          // schedule_x 테이블 업데이트 (원본 작성자 username도 수정)
          await db.query(
            'UPDATE schedule_x SET username = ?, content = ?, image_urls = ? WHERE schedule_id = ?',
            [fetchUsername, newContent, newImageUrls, row.schedule_id]
          );

          // Meilisearch 동기화
          await syncScheduleById(meilisearch, db, row.schedule_id);

          updated++;
          fastify.log.info(`리트윗 재수집 완료: schedule_id=${row.schedule_id}, post_id=${row.post_id}`);

          // Nitter 부하 방지
          await new Promise(r => setTimeout(r, 500));
        } catch (err) {
          errors.push({ scheduleId: row.schedule_id, postId: row.post_id, error: err.message });
          fastify.log.error(`리트윗 재수집 실패 (${row.schedule_id}): ${err.message}`);
        }
      }

      logActivity(db, {
        actor: 'admin',
        action: 'update',
        category: 'schedule',
        targetType: 'x_schedule',
        summary: `리트윗 재수집: ${updated}/${rows.length}건 완료`,
      });

      return { success: true, total: rows.length, updated, errors };
    } catch (err) {
      fastify.log.error(`리트윗 재수집 오류: ${err.message}`);
      return serverError(reply, err.message);
    }
  });
}
