/**
 * 스케줄 서비스
 * 스케줄 관련 비즈니스 로직
 */
import config, { CATEGORY_IDS } from '../config/index.js';
import { getOrSet, cacheKeys, TTL } from '../utils/cache.js';

// ==================== 공통 포맷팅 함수 ====================

/**
 * 날짜 문자열 정규화
 * @param {Date|string} date - 날짜
 * @returns {string} YYYY-MM-DD 형식
 */
export function normalizeDate(date) {
  if (!date) return '';
  if (date instanceof Date) {
    return date.toISOString().split('T')[0];
  }
  return String(date).split('T')[0];
}

/**
 * datetime 생성 (date + time)
 * @param {Date|string} date - 날짜
 * @param {string} time - 시간 (HH:mm:ss)
 * @returns {string} YYYY-MM-DDTHH:mm:ss 또는 YYYY-MM-DD
 */
export function buildDatetime(date, time) {
  const dateStr = normalizeDate(date);
  return time ? `${dateStr}T${time}` : dateStr;
}

/**
 * source 객체 생성
 * @param {object} schedule - 일정 원본 데이터
 * @returns {object|null} { name, url } 또는 null
 */
export function buildSource(schedule) {
  const { category_id, youtube_video_id, youtube_video_type, youtube_channel, x_post_id } = schedule;

  if (category_id === CATEGORY_IDS.YOUTUBE && youtube_video_id) {
    const url = youtube_video_type === 'shorts'
      ? `https://www.youtube.com/shorts/${youtube_video_id}`
      : `https://www.youtube.com/watch?v=${youtube_video_id}`;
    return {
      name: youtube_channel || 'YouTube',
      url,
    };
  }

  if (category_id === CATEGORY_IDS.X && x_post_id) {
    return {
      name: '',
      url: `https://x.com/${config.x.defaultUsername}/status/${x_post_id}`,
    };
  }

  return null;
}

/**
 * 단일 일정 포맷팅 (공통)
 * @param {object} rawSchedule - DB에서 조회한 원본 일정
 * @param {string[]} members - 멤버 이름 배열
 * @returns {object} 포맷된 일정 객체
 */
export function formatSchedule(rawSchedule, members = []) {
  return {
    id: rawSchedule.id,
    title: rawSchedule.title,
    datetime: buildDatetime(rawSchedule.date, rawSchedule.time),
    category: {
      id: rawSchedule.category_id,
      name: rawSchedule.category_name,
      color: rawSchedule.category_color,
    },
    source: buildSource(rawSchedule),
    members,
  };
}

/**
 * 멤버 맵 조회 (일정 ID → 멤버 이름 배열)
 * @param {object} db - 데이터베이스 연결
 * @param {number[]} scheduleIds - 일정 ID 배열
 * @returns {object} { scheduleId: [memberName, ...] }
 */
export async function buildMemberMap(db, scheduleIds) {
  if (!scheduleIds || scheduleIds.length === 0) {
    return {};
  }

  const [scheduleMembers] = await db.query(`
    SELECT sm.schedule_id, m.name
    FROM schedule_members sm
    JOIN members m ON sm.member_id = m.id
    WHERE sm.schedule_id IN (?)
    ORDER BY m.id
  `, [scheduleIds]);

  const memberMap = {};
  for (const sm of scheduleMembers) {
    if (!memberMap[sm.schedule_id]) {
      memberMap[sm.schedule_id] = [];
    }
    memberMap[sm.schedule_id].push(sm.name);
  }

  return memberMap;
}

/**
 * 일정 목록 포맷팅 (공통)
 * @param {object[]} rawSchedules - DB에서 조회한 원본 일정 배열
 * @param {object} memberMap - 멤버 맵
 * @returns {object[]} 포맷된 일정 배열
 */
export function formatSchedules(rawSchedules, memberMap) {
  return rawSchedules.map(s => formatSchedule(s, memberMap[s.id] || []));
}

// ==================== 카테고리 ====================

/**
 * 카테고리 목록 조회 (캐시 적용)
 * @param {object} db - 데이터베이스 연결
 * @param {object} redis - Redis 클라이언트 (선택적)
 * @returns {array} 카테고리 목록
 */
export async function getCategories(db, redis = null) {
  const fetchCategories = async () => {
    const [categories] = await db.query(
      'SELECT id, name, color, sort_order FROM schedule_categories ORDER BY sort_order ASC, id ASC'
    );
    return categories;
  };

  if (redis) {
    return getOrSet(redis, cacheKeys.categories, fetchCategories, TTL.VERY_LONG);
  }
  return fetchCategories();
}

// ==================== 일정 상세 ====================

/**
 * 일정 상세 조회
 * @param {object} db - 데이터베이스 연결
 * @param {number} id - 일정 ID
 * @param {Function} getXProfile - X 프로필 조회 함수 (선택적)
 * @returns {object|null} 일정 상세 또는 null
 */
export async function getScheduleDetail(db, id, getXProfile = null) {
  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,
      sx.content as x_content,
      sx.image_urls as x_image_urls
    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 null;
  }

  const s = schedules[0];

  // 멤버 정보 조회
  const [members] = await db.query(`
    SELECT m.id, m.name
    FROM schedule_members sm
    JOIN members m ON sm.member_id = m.id
    WHERE sm.schedule_id = ?
    ORDER BY m.id
  `, [id]);

  // 공통 필드
  const result = {
    id: s.id,
    title: s.title,
    datetime: buildDatetime(s.date, s.time),
    category: {
      id: s.category_id,
      name: s.category_name,
      color: s.category_color,
    },
    members,
    createdAt: s.created_at,
    updatedAt: s.updated_at,
  };

  // 카테고리별 추가 필드
  if (s.category_id === CATEGORY_IDS.YOUTUBE && s.youtube_video_id) {
    result.videoId = s.youtube_video_id;
    result.videoType = s.youtube_video_type;
    result.channelName = s.youtube_channel;
    result.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}`;
  } else if (s.category_id === CATEGORY_IDS.X && s.x_post_id) {
    const username = config.x.defaultUsername;
    result.postId = s.x_post_id;
    result.content = s.x_content || null;
    result.imageUrls = s.x_image_urls ? JSON.parse(s.x_image_urls) : [];
    result.postUrl = `https://x.com/${username}/status/${s.x_post_id}`;

    if (getXProfile) {
      const profile = await getXProfile(username);
      if (profile) {
        result.profile = {
          username: profile.username,
          displayName: profile.displayName,
          avatarUrl: profile.avatarUrl,
        };
      }
    }
  }

  return result;
}

// ==================== 일정 목록 조회 ====================

/** 일정 목록 조회용 공통 SQL */
const SCHEDULE_LIST_SQL = `
  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
`;

/**
 * 월별 일정 조회 (생일 포함)
 * @param {object} db - 데이터베이스 연결
 * @param {number} year - 연도
 * @param {number} month - 월
 * @returns {object} { schedules: [] }
 */
export async function getMonthlySchedules(db, year, month) {
  const startDate = `${year}-${String(month).padStart(2, '0')}-01`;
  const endDate = new Date(year, month, 0).toISOString().split('T')[0];

  // 일정 조회
  const [rawSchedules] = await db.query(
    `${SCHEDULE_LIST_SQL} WHERE s.date BETWEEN ? AND ? ORDER BY s.date ASC, s.time ASC`,
    [startDate, endDate]
  );

  // 멤버 맵 조회
  const memberMap = await buildMemberMap(db, rawSchedules.map(s => s.id));

  // 일정 포맷팅
  const schedules = formatSchedules(rawSchedules, memberMap);

  // 생일 조회 및 추가
  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]);

  for (const member of birthdays) {
    const birthDate = new Date(member.birth_date);
    if (year < birthDate.getFullYear()) continue;

    const birthdayDate = new Date(year, birthDate.getMonth(), birthDate.getDate());

    schedules.push({
      id: `birthday-${member.id}`,
      title: `HAPPY ${member.name_en} DAY`,
      datetime: birthdayDate.toISOString().split('T')[0],
      category: {
        id: CATEGORY_IDS.BIRTHDAY,
        name: '생일',
        color: '#f472b6',
      },
      source: null,
      members: [member.name],
      is_birthday: true,
      member_image: member.image_url,
    });
  }

  // 날짜순 정렬
  schedules.sort((a, b) => a.datetime.localeCompare(b.datetime));

  return { schedules };
}

/**
 * 다가오는 일정 조회
 * @param {object} db - 데이터베이스 연결
 * @param {string} startDate - 시작 날짜
 * @param {number} limit - 조회 개수
 * @returns {object} { schedules: [] }
 */
export async function getUpcomingSchedules(db, startDate, limit) {
  // 일정 조회
  const [rawSchedules] = await db.query(
    `${SCHEDULE_LIST_SQL} WHERE s.date >= ? ORDER BY s.date ASC, s.time ASC LIMIT ?`,
    [startDate, limit]
  );

  // 멤버 맵 조회
  const memberMap = await buildMemberMap(db, rawSchedules.map(s => s.id));

  // 일정 포맷팅
  const schedules = formatSchedules(rawSchedules, memberMap);

  return { schedules };
}
