/**
 * 일정 라우트
 * GET: 공개, POST/PUT/DELETE: 인증 필요
 */
import suggestionsRoutes from './suggestions.js';
import { searchSchedules, syncAllSchedules } from '../../services/meilisearch/index.js';

export default async function schedulesRoutes(fastify) {
  const { db, meilisearch, redis } = fastify;

  // 추천 검색어 라우트 등록
  fastify.register(suggestionsRoutes, { prefix: '/suggestions' });

  /**
   * GET /api/schedules
   * 검색 모드: search 파라미터가 있으면 Meilisearch 검색
   * 월별 조회 모드: year, month 파라미터로 월별 조회
   */
  fastify.get('/', {
    schema: {
      tags: ['schedules'],
      summary: '일정 조회 (검색 또는 월별)',
      querystring: {
        type: 'object',
        properties: {
          search: { type: 'string', description: '검색어' },
          year: { type: 'integer', description: '년도' },
          month: { type: 'integer', minimum: 1, maximum: 12, description: '월' },
          offset: { type: 'integer', default: 0, description: '페이지 오프셋' },
          limit: { type: 'integer', default: 100, description: '결과 개수' },
        },
      },
    },
  }, async (request, reply) => {
    const { search, year, month, offset = 0, limit = 100 } = request.query;

    // 검색 모드
    if (search && search.trim()) {
      return await handleSearch(fastify, search.trim(), parseInt(offset), parseInt(limit));
    }

    // 월별 조회 모드
    if (!year || !month) {
      return reply.code(400).send({ error: 'search 또는 year/month는 필수입니다.' });
    }

    return await handleMonthlySchedules(db, parseInt(year), parseInt(month));
  });

  /**
   * POST /api/schedules/sync-search
   * Meilisearch 전체 동기화 (관리자 전용)
   */
  fastify.post('/sync-search', {
    schema: {
      tags: ['schedules'],
      summary: 'Meilisearch 전체 동기화',
      security: [{ bearerAuth: [] }],
    },
    preHandler: [fastify.authenticate],
  }, async (request, reply) => {
    const count = await syncAllSchedules(meilisearch, db);
    return { success: true, synced: count };
  });

  /**
   * GET /api/schedules/:id
   * 일정 상세 조회
   */
  fastify.get('/:id', {
    schema: {
      tags: ['schedules'],
      summary: '일정 상세 조회',
    },
  }, async (request, reply) => {
    const { id } = request.params;

    const [schedules] = await db.query(`
      SELECT
        s.*,
        c.name as category_name,
        c.color as category_color,
        sy.channel_name as youtube_channel,
        sy.video_id as youtube_video_id,
        sy.video_type as youtube_video_type,
        sx.post_id as x_post_id
      FROM schedules s
      LEFT JOIN schedule_categories c ON s.category_id = c.id
      LEFT JOIN schedule_youtube sy ON s.id = sy.schedule_id
      LEFT JOIN schedule_x sx ON s.id = sx.schedule_id
      WHERE s.id = ?
    `, [id]);

    if (schedules.length === 0) {
      return reply.code(404).send({ error: '일정을 찾을 수 없습니다.' });
    }

    const s = schedules[0];
    const result = {
      id: s.id,
      title: s.title,
      date: s.date,
      time: s.time,
      category: {
        id: s.category_id,
        name: s.category_name,
        color: s.category_color,
      },
      created_at: s.created_at,
      updated_at: s.updated_at,
    };

    // source 정보 추가 (YouTube: 2, X: 3)
    if (s.category_id === 2 && s.youtube_video_id) {
      const videoUrl = s.youtube_video_type === 'shorts'
        ? `https://www.youtube.com/shorts/${s.youtube_video_id}`
        : `https://www.youtube.com/watch?v=${s.youtube_video_id}`;
      result.source = {
        name: s.youtube_channel || 'YouTube',
        url: videoUrl,
      };
    } else if (s.category_id === 3 && s.x_post_id) {
      result.source = {
        name: 'X',
        url: `https://x.com/realfromis_9/status/${s.x_post_id}`,
      };
    }

    return result;
  });
}

/**
 * 검색 처리
 */
async function handleSearch(fastify, query, offset, limit) {
  const { db, meilisearch, redis } = fastify;

  // 첫 페이지 검색 시에만 검색어 저장 (bi-gram 학습)
  if (offset === 0) {
    // 비동기로 저장 (응답 지연 방지)
    saveSearchQueryAsync(fastify, query);
  }

  // Meilisearch 검색
  const results = await searchSchedules(meilisearch, db, query, { limit: 1000 });

  // 페이징 적용
  const paginatedHits = results.hits.slice(offset, offset + limit);

  return {
    schedules: paginatedHits,
    total: results.total,
    offset,
    limit,
    hasMore: offset + paginatedHits.length < results.total,
  };
}

/**
 * 검색어 비동기 저장
 */
async function saveSearchQueryAsync(fastify, query) {
  try {
    // suggestions 서비스의 saveSearchQuery 사용
    const { SuggestionService } = await import('../../services/suggestions/index.js');
    const service = new SuggestionService(fastify.db, fastify.redis);
    await service.saveSearchQuery(query);
  } catch (err) {
    console.error('[Search] 검색어 저장 실패:', err.message);
  }
}

/**
 * 월별 일정 조회 (생일 포함)
 */
async function handleMonthlySchedules(db, year, month) {
  const startDate = `${year}-${String(month).padStart(2, '0')}-01`;
  const endDate = new Date(year, month, 0).toISOString().split('T')[0];

  // 일정 조회 (YouTube, X 소스 정보 포함)
  const [schedules] = await db.query(`
    SELECT
      s.id,
      s.title,
      s.date,
      s.time,
      s.category_id,
      c.name as category_name,
      c.color as category_color,
      sy.channel_name as youtube_channel,
      sy.video_id as youtube_video_id,
      sy.video_type as youtube_video_type,
      sx.post_id as x_post_id
    FROM schedules s
    LEFT JOIN schedule_categories c ON s.category_id = c.id
    LEFT JOIN schedule_youtube sy ON s.id = sy.schedule_id
    LEFT JOIN schedule_x sx ON s.id = sx.schedule_id
    WHERE s.date BETWEEN ? AND ?
    ORDER BY s.date ASC, s.time ASC
  `, [startDate, endDate]);

  // 생일 조회
  const [birthdays] = await db.query(`
    SELECT m.id, m.name, m.name_en, m.birth_date,
           i.thumb_url as image_url
    FROM members m
    LEFT JOIN images i ON m.image_id = i.id
    WHERE m.is_former = 0 AND MONTH(m.birth_date) = ?
  `, [month]);

  // 날짜별로 그룹화
  const grouped = {};

  // 일정 추가
  for (const s of schedules) {
    const dateKey = s.date instanceof Date
      ? s.date.toISOString().split('T')[0]
      : s.date;

    if (!grouped[dateKey]) {
      grouped[dateKey] = {
        categories: [],
        schedules: [],
      };
    }

    const schedule = {
      id: s.id,
      title: s.title,
      time: s.time,
      category: {
        id: s.category_id,
        name: s.category_name,
        color: s.category_color,
      },
    };

    // source 정보 추가 (YouTube: 2, X: 3)
    if (s.category_id === 2 && s.youtube_video_id) {
      const videoUrl = s.youtube_video_type === 'shorts'
        ? `https://www.youtube.com/shorts/${s.youtube_video_id}`
        : `https://www.youtube.com/watch?v=${s.youtube_video_id}`;
      schedule.source = {
        name: s.youtube_channel || 'YouTube',
        url: videoUrl,
      };
    } else if (s.category_id === 3 && s.x_post_id) {
      schedule.source = {
        name: 'X',
        url: `https://x.com/realfromis_9/status/${s.x_post_id}`,
      };
    }

    grouped[dateKey].schedules.push(schedule);

    // 카테고리 카운트
    const existingCategory = grouped[dateKey].categories.find(c => c.id === s.category_id);
    if (existingCategory) {
      existingCategory.count++;
    } else {
      grouped[dateKey].categories.push({
        id: s.category_id,
        name: s.category_name,
        color: s.category_color,
        count: 1,
      });
    }
  }

  // 생일 일정 추가
  for (const member of birthdays) {
    const birthDate = new Date(member.birth_date);
    const birthdayThisYear = new Date(year, birthDate.getMonth(), birthDate.getDate());
    const dateKey = birthdayThisYear.toISOString().split('T')[0];

    if (!grouped[dateKey]) {
      grouped[dateKey] = {
        categories: [],
        schedules: [],
      };
    }

    // 생일 카테고리 (id: 8)
    const BIRTHDAY_CATEGORY = {
      id: 8,
      name: '생일',
      color: '#f472b6',
    };

    const birthdaySchedule = {
      id: `birthday-${member.id}`,
      title: `HAPPY ${member.name_en} DAY`,
      time: null,
      category: BIRTHDAY_CATEGORY,
      is_birthday: true,
      member_name: member.name,
      member_image: member.image_url,
    };

    grouped[dateKey].schedules.push(birthdaySchedule);

    // 생일 카테고리 카운트
    const existingBirthdayCategory = grouped[dateKey].categories.find(c => c.id === 8);
    if (existingBirthdayCategory) {
      existingBirthdayCategory.count++;
    } else {
      grouped[dateKey].categories.push({
        ...BIRTHDAY_CATEGORY,
        count: 1,
      });
    }
  }

  return grouped;
}
