/**
 * Meilisearch 검색 서비스
 * - 일정 검색 (멤버 별명 → 이름 변환)
 * - 영문 자판 → 한글 변환
 * - 유사도 필터링
 * - 일정 동기화
 */
import Inko from 'inko';

const inko = new Inko();
const INDEX_NAME = 'schedules';

/**
 * 영문 자판으로 입력된 검색어인지 확인
 */
function isEnglishKeyboard(text) {
  const englishChars = text.match(/[a-zA-Z]/g) || [];
  const koreanChars = text.match(/[가-힣ㄱ-ㅎㅏ-ㅣ]/g) || [];
  return englishChars.length > 0 && koreanChars.length === 0;
}

/**
 * 별명/이름으로 멤버 이름 조회
 */
export async function resolveMemberNames(db, query) {
  const searchTerm = `%${query}%`;
  const [members] = await db.query(`
    SELECT DISTINCT m.name
    FROM members m
    LEFT JOIN member_nicknames mn ON m.id = mn.member_id
    WHERE m.name LIKE ? OR mn.nickname LIKE ?
  `, [searchTerm, searchTerm]);

  return members.map(m => m.name);
}

/**
 * 일정 검색
 * @param {object} meilisearch - Meilisearch 클라이언트
 * @param {object} db - DB 연결 풀
 * @param {string} query - 검색어
 * @param {object} options - 검색 옵션
 */
export async function searchSchedules(meilisearch, db, query, options = {}) {
  const { limit = 1000, offset = 0 } = options;

  try {
    const index = meilisearch.index(INDEX_NAME);

    const searchOptions = {
      limit,
      offset: 0, // 내부적으로 전체 검색 후 필터링
      attributesToRetrieve: ['*'],
      showRankingScore: true,
    };

    // 검색어 목록 구성
    const searchQueries = [query];

    // 영문 자판 입력 → 한글 변환
    if (isEnglishKeyboard(query)) {
      const koreanQuery = inko.en2ko(query);
      if (koreanQuery !== query) {
        searchQueries.push(koreanQuery);
      }
    }

    // 별명 → 멤버 이름 변환
    const memberNames = await resolveMemberNames(db, query);
    for (const name of memberNames) {
      if (!searchQueries.includes(name)) {
        searchQueries.push(name);
      }
    }

    // 각 검색어로 검색 후 병합
    const allHits = new Map(); // id 기준 중복 제거

    for (const q of searchQueries) {
      const results = await index.search(q, searchOptions);
      for (const hit of results.hits) {
        // 더 높은 점수로 업데이트
        if (!allHits.has(hit.id) || allHits.get(hit.id)._rankingScore < hit._rankingScore) {
          allHits.set(hit.id, hit);
        }
      }
    }

    // 유사도 0.5 미만 필터링
    let filteredHits = Array.from(allHits.values())
      .filter(hit => hit._rankingScore >= 0.5);

    // 유사도 순 정렬
    filteredHits.sort((a, b) => (b._rankingScore || 0) - (a._rankingScore || 0));

    const total = filteredHits.length;

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

    // 응답 형식 변환
    const formattedHits = paginatedHits.map(formatScheduleResponse);

    return {
      hits: formattedHits,
      total,
      offset,
      limit,
      hasMore: offset + paginatedHits.length < total,
    };
  } catch (err) {
    console.error('[Meilisearch] 검색 오류:', err.message);
    return { hits: [], total: 0, offset: 0, limit, hasMore: false };
  }
}

/**
 * 검색 결과 응답 형식 변환
 */
function formatScheduleResponse(hit) {
  // date + time 합치기
  let datetime = null;
  if (hit.date) {
    const dateStr = hit.date instanceof Date
      ? hit.date.toISOString().split('T')[0]
      : String(hit.date).split('T')[0];

    if (hit.time) {
      datetime = `${dateStr}T${hit.time}`;
    } else {
      datetime = dateStr;
    }
  }

  // member_names를 배열로 변환
  const members = hit.member_names
    ? hit.member_names.split(',').map(name => name.trim()).filter(Boolean)
    : [];

  return {
    id: hit.id,
    title: hit.title,
    datetime,
    category: {
      id: hit.category_id,
      name: hit.category_name,
      color: hit.category_color,
    },
    source_name: hit.source_name || null,
    members,
    _rankingScore: hit._rankingScore,
  };
}

/**
 * 일정 추가/업데이트
 */
export async function addOrUpdateSchedule(meilisearch, schedule) {
  try {
    const index = meilisearch.index(INDEX_NAME);

    const document = {
      id: schedule.id,
      title: schedule.title,
      description: schedule.description || '',
      date: schedule.date,
      time: schedule.time || '',
      category_id: schedule.category_id,
      category_name: schedule.category_name || '',
      category_color: schedule.category_color || '',
      source_name: schedule.source_name || '',
      member_names: schedule.member_names || '',
    };

    await index.addDocuments([document]);
    console.log(`[Meilisearch] 일정 추가/업데이트: ${schedule.id}`);
  } catch (err) {
    console.error('[Meilisearch] 문서 추가 오류:', err.message);
  }
}

/**
 * 일정 삭제
 */
export async function deleteSchedule(meilisearch, scheduleId) {
  try {
    const index = meilisearch.index(INDEX_NAME);
    await index.deleteDocument(scheduleId);
    console.log(`[Meilisearch] 일정 삭제: ${scheduleId}`);
  } catch (err) {
    console.error('[Meilisearch] 문서 삭제 오류:', err.message);
  }
}

/**
 * 전체 일정 동기화
 */
export async function syncAllSchedules(meilisearch, db) {
  try {
    // DB에서 모든 일정 조회
    const [schedules] = await db.query(`
      SELECT
        s.id,
        s.title,
        s.description,
        s.date,
        s.time,
        s.category_id,
        c.name as category_name,
        c.color as category_color,
        sy.channel_name as source_name,
        GROUP_CONCAT(DISTINCT m.name ORDER BY m.id SEPARATOR ',') as member_names
      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_members sm ON s.id = sm.schedule_id
      LEFT JOIN members m ON sm.member_id = m.id
      GROUP BY s.id
    `);

    const index = meilisearch.index(INDEX_NAME);

    // 기존 문서 모두 삭제
    await index.deleteAllDocuments();

    // 문서 변환
    const documents = schedules.map(s => ({
      id: s.id,
      title: s.title,
      description: s.description || '',
      date: s.date instanceof Date ? s.date.toISOString().split('T')[0] : s.date,
      time: s.time || '',
      category_id: s.category_id,
      category_name: s.category_name || '',
      category_color: s.category_color || '',
      source_name: s.source_name || '',
      member_names: s.member_names || '',
    }));

    // 일괄 추가
    await index.addDocuments(documents);
    console.log(`[Meilisearch] ${documents.length}개 일정 동기화 완료`);

    return documents.length;
  } catch (err) {
    console.error('[Meilisearch] 동기화 오류:', err.message);
    return 0;
  }
}
