import config from '../../config/index.js';
import { formatDate, formatTime } from '../../utils/date.js';

const API_KEY = config.google.apiKey;
const API_BASE = 'https://www.googleapis.com/youtube/v3';
const FETCH_TIMEOUT = 10000;

/**
 * 타임아웃이 있는 fetch (업스트림 행으로 봇/요청이 무한 대기하는 것 방지)
 */
async function fetchWithTimeout(url, options = {}) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
  try {
    return await fetch(url, { ...options, signal: controller.signal });
  } finally {
    clearTimeout(timeoutId);
  }
}

/**
 * ISO 8601 duration (PT1M30S) → 초 변환
 */
function parseDuration(duration) {
  const match = duration.match(/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/);
  if (!match) return 0;
  return (
    parseInt(match[1] || 0) * 3600 +
    parseInt(match[2] || 0) * 60 +
    parseInt(match[3] || 0)
  );
}

/**
 * 영상 URL 생성
 */
function getVideoUrl(videoId, isShorts) {
  return isShorts
    ? `https://www.youtube.com/shorts/${videoId}`
    : `https://www.youtube.com/watch?v=${videoId}`;
}

/**
 * 채널의 업로드 플레이리스트 ID 조회
 */
export async function getUploadsPlaylistId(channelId) {
  const url = `${API_BASE}/channels?part=contentDetails&id=${channelId}&key=${API_KEY}`;
  const res = await fetchWithTimeout(url);
  const data = await res.json();

  if (data.error) {
    throw new Error(data.error.message);
  }
  if (!data.items?.length) {
    throw new Error('채널을 찾을 수 없습니다');
  }

  return data.items[0].contentDetails.relatedPlaylists.uploads;
}

/**
 * 핸들로 채널 조회
 * @param {string} handle - @username 형식 (@ 제외)
 */
export async function getChannelByHandle(handle) {
  // @ 제거
  const cleanHandle = handle.startsWith('@') ? handle.slice(1) : handle;
  const url = `${API_BASE}/channels?part=snippet,brandingSettings&forHandle=${cleanHandle}&key=${API_KEY}`;
  const res = await fetchWithTimeout(url);
  const data = await res.json();

  if (data.error) {
    throw new Error(data.error.message);
  }
  if (!data.items?.length) {
    throw new Error('채널을 찾을 수 없습니다');
  }

  const channel = data.items[0];
  const { snippet, brandingSettings } = channel;

  // 배너 URL에 고해상도 파라미터 추가
  const bannerBase = brandingSettings?.image?.bannerExternalUrl;
  const bannerUrl = bannerBase ? `${bannerBase}=w2560` : null;

  return {
    channelId: channel.id,
    handle: cleanHandle,
    title: snippet.title,
    description: snippet.description,
    thumbnailUrl: snippet.thumbnails?.high?.url || snippet.thumbnails?.default?.url,
    bannerUrl,
  };
}

/**
 * 채널 정보 조회 (배너 이미지 포함)
 */
export async function getChannelInfo(channelId) {
  const url = `${API_BASE}/channels?part=snippet,brandingSettings&id=${channelId}&key=${API_KEY}`;
  const res = await fetchWithTimeout(url);
  const data = await res.json();

  if (data.error) {
    throw new Error(data.error.message);
  }
  if (!data.items?.length) {
    throw new Error('채널을 찾을 수 없습니다');
  }

  const channel = data.items[0];
  const { snippet, brandingSettings } = channel;

  // 배너 URL에 고해상도 파라미터 추가
  const bannerBase = brandingSettings?.image?.bannerExternalUrl;
  const bannerUrl = bannerBase ? `${bannerBase}=w2560` : null;

  return {
    channelId,
    title: snippet.title,
    description: snippet.description,
    thumbnailUrl: snippet.thumbnails?.high?.url || snippet.thumbnails?.default?.url,
    bannerUrl,
  };
}

/**
 * 영상 ID 목록으로 duration 조회 (Shorts 판별용)
 */
async function getVideoDurations(videoIds) {
  const url = `${API_BASE}/videos?part=contentDetails&id=${videoIds.join(',')}&key=${API_KEY}`;
  const res = await fetchWithTimeout(url);
  const data = await res.json();

  const durations = {};
  if (data.items) {
    for (const v of data.items) {
      const seconds = parseDuration(v.contentDetails.duration);
      durations[v.id] = seconds <= 60;
    }
  }
  return durations;
}

/**
 * 최근 영상 ID 목록만 조회 (Activities API - 1 unit)
 * @param {string} channelId - 채널 ID
 * @param {number} maxResults - 최대 결과 수
 */
export async function fetchRecentVideoIds(channelId, maxResults = 10) {
  const fetchCount = Math.min(maxResults * 2, 50);
  const url = `${API_BASE}/activities?part=snippet,contentDetails&channelId=${channelId}&type=upload&maxResults=${fetchCount}&key=${API_KEY}`;
  const res = await fetchWithTimeout(url);
  const data = await res.json();

  if (data.error) {
    throw new Error(data.error.message);
  }

  return (data.items || [])
    .filter(item => item.snippet.type === 'upload')
    .slice(0, maxResults)
    .map(item => item.contentDetails.upload.videoId);
}

/**
 * 전체 영상 조회 (페이지네이션)
 * @param {string} channelId - 채널 ID
 * @param {string} uploadsPlaylistId - 캐싱된 uploads playlist ID (선택)
 */
export async function fetchAllVideos(channelId, uploadsPlaylistId = null) {
  const uploadsId = uploadsPlaylistId || await getUploadsPlaylistId(channelId);
  const videos = [];
  let pageToken = '';

  do {
    const url = `${API_BASE}/playlistItems?part=snippet&playlistId=${uploadsId}&maxResults=50&key=${API_KEY}${pageToken ? `&pageToken=${pageToken}` : ''}`;
    const res = await fetchWithTimeout(url);
    const data = await res.json();

    if (data.error) {
      throw new Error(data.error.message);
    }

    const videoIds = data.items.map(item => item.snippet.resourceId.videoId);
    const shortsMap = await getVideoDurations(videoIds);

    for (const item of data.items) {
      const { snippet } = item;
      const videoId = snippet.resourceId.videoId;
      const isShorts = shortsMap[videoId] || false;
      const publishedAt = new Date(snippet.publishedAt);

      videos.push({
        videoId,
        title: snippet.title,
        description: snippet.description || '',
        channelId: snippet.channelId,
        channelTitle: snippet.channelTitle,
        publishedAt,
        date: formatDate(publishedAt),
        time: formatTime(publishedAt),
        videoType: isShorts ? 'shorts' : 'video',
        videoUrl: getVideoUrl(videoId, isShorts),
      });
    }

    pageToken = data.nextPageToken || '';
  } while (pageToken);

  // 과거순 정렬
  videos.sort((a, b) => a.publishedAt - b.publishedAt);
  return videos;
}

/**
 * 단일 영상 정보 조회
 */
export async function fetchVideoInfo(videoId) {
  const url = `${API_BASE}/videos?part=snippet,contentDetails&id=${videoId}&key=${API_KEY}`;
  const res = await fetchWithTimeout(url);
  const data = await res.json();

  if (!data.items?.length) {
    return null;
  }

  const video = data.items[0];
  const { snippet, contentDetails } = video;
  const seconds = parseDuration(contentDetails.duration);
  const isShorts = seconds > 0 && seconds <= 60;
  const publishedAt = new Date(snippet.publishedAt);

  return {
    videoId,
    title: snippet.title,
    description: snippet.description || '',
    channelId: snippet.channelId,
    channelTitle: snippet.channelTitle,
    publishedAt,
    date: formatDate(publishedAt),
    time: formatTime(publishedAt),
    videoType: isShorts ? 'shorts' : 'video',
    videoUrl: getVideoUrl(videoId, isShorts),
  };
}
