// Native fetch available in Node 20+
import { getDb } from '../database/database';
import { localTimestamp } from '../utils/time';

export interface ContentInfo {
  keyword: string;
  title: string;
  description: string;
  tags: string[];
  cover: string;
  source: string;
  /** TMDB 详情页链接 */
  tmdb_url?: string;
  /** 评分 e.g. "7.3" */
  rating?: string;
  /** 评分人数 e.g. "12345" */
  rating_count?: string;
  /** 发布年份 e.g. "2025" */
  year?: string;
  /** 类型标签 e.g. ["动作", "科幻"] */
  genres?: string[];
  /** 导演 e.g. "克里斯托弗·诺兰" */
  directors?: string;
  /** 演员（前5个） e.g. "基里安·墨菲 / 艾米莉·布朗特" */
  actors?: string;
  /** 制片国家/地区 e.g. "美国 / 英国" */
  region?: string;
  /** 片长 e.g. "180分钟" */
  duration?: string;
}

const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;

export async function getContentInfo(keyword: string): Promise<ContentInfo | null> {
  if (!keyword || keyword.length < 1) return null;

  const db = getDb();
  const tmdbToken = (db.prepare('SELECT value FROM system_configs WHERE key = ?').get('tmdb_api_token') as any)?.value || '';
  if (!tmdbToken) return null;

  const cached = db.prepare('SELECT * FROM content_cache WHERE keyword = ?').get(keyword) as any;
  if (cached) {
    const age = Date.now() - new Date(cached.updated_at + 'Z').getTime();
    if (age < CACHE_TTL_MS) {
      return rowToContentInfo(cached);
    }
  }

  try {
    const info = await fetchFromTMDB(keyword, tmdbToken);
    if (info) {
      db.prepare(`
        INSERT OR REPLACE INTO content_cache
          (keyword, title, description, tags, cover, douban_url, source, updated_at,
           rating, rating_count, year, genres, directors, actors, region, duration)
        VALUES (?, ?, ?, ?, ?, ?, 'tmdb', ?,
                ?, ?, ?, ?, ?, ?, ?, ?)
      `).run(
        keyword, info.title, info.description, JSON.stringify(info.tags), info.cover, info.tmdb_url || '', localTimestamp(),
        info.rating || '', info.rating_count || '', info.year || '',
        JSON.stringify(info.genres || []), info.directors || '', info.actors || '',
        info.region || '', info.duration || ''
      );
      return info;
    }
  } catch (err) {
    console.error(`[Content] Failed to fetch for "${keyword}":`, err);
  }
  return null;
}

function rowToContentInfo(row: any): ContentInfo {
  return {
    keyword: row.keyword,
    title: row.title || '',
    description: row.description || '',
    tags: safeParseTags(row.tags),
    cover: row.cover || '',
    source: row.source || (row.title ? 'tmdb' : 'cache'),
    tmdb_url: row.douban_url || '',
    rating: row.rating || '',
    rating_count: row.rating_count || '',
    year: row.year || '',
    genres: safeParseTags(row.genres),
    directors: row.directors || '',
    actors: row.actors || '',
    region: row.region || '',
    duration: row.duration || '',
  };
}

async function fetchFromTMDB(keyword: string, tmdbToken: string): Promise<ContentInfo | null> {
  // Step 1: TMDB search — search both movie and TV in parallel
  let movieResults: any[] = [];
  let tvResults: any[] = [];

  try {
    const searchUrl = `https://api.themoviedb.org/3/search/movie?query=${encodeURIComponent(keyword)}&language=zh-CN&page=1`;
    const searchResp = await fetch(searchUrl, {
      headers: { 'Authorization': `Bearer ${tmdbToken}` },
      signal: AbortSignal.timeout(8000),
    });
    if (searchResp.ok) {
      const searchData = await searchResp.json() as any;
      if (Array.isArray(searchData.results)) {
        movieResults = searchData.results;
      }
    }
  } catch {
    console.warn(`[Content] TMDB movie search failed for "${keyword}"`);
  }

  try {
    const searchUrl = `https://api.themoviedb.org/3/search/tv?query=${encodeURIComponent(keyword)}&language=zh-CN&page=1`;
    const searchResp = await fetch(searchUrl, {
      headers: { 'Authorization': `Bearer ${tmdbToken}` },
      signal: AbortSignal.timeout(8000),
    });
    if (searchResp.ok) {
      const searchData = await searchResp.json() as any;
      if (Array.isArray(searchData.results)) {
        tvResults = searchData.results;
      }
    }
  } catch {
    console.warn(`[Content] TMDB TV search failed for "${keyword}"`);
  }

  // Step 2: Score and rank all results
  const isChineseKeyword = /[\u4e00-\u9fff]/.test(keyword);
  const kwLower = keyword.toLowerCase();

  // Score function: higher = better match
  function scoreResult(item: any, type: 'tv' | 'movie'): number {
    const name = (type === 'tv' ? (item.name || item.original_name || '') : (item.title || item.original_title || '')).toLowerCase();
    // Exact match gets highest priority
    if (name === kwLower) return 100;
    // Name starts with keyword
    if (name.startsWith(kwLower)) return 80;
    // Name contains keyword as a standalone segment
    if (name.includes(kwLower)) return 60;
    // Keyword contains significant portion of name
    const cleanName = name.replace(/[^a-z0-9\u4e00-\u9fff]/g, '');
    if (kwLower.includes(cleanName) && cleanName.length >= 2) return 40;
    // Partial match
    if (name.includes(kwLower) || kwLower.includes(cleanName)) return 20;
    return 0;
  }

  // Score all TV results
  const scoredTV = tvResults.map((r: any) => ({ item: r, score: scoreResult(r, 'tv') })).filter(r => r.score > 0);
  // Score all movie results
  const scoredMovie = movieResults.map((r: any) => ({ item: r, score: scoreResult(r, 'movie') })).filter(r => r.score > 0);

  // Sort by score descending
  scoredTV.sort((a, b) => b.score - a.score);
  scoredMovie.sort((a, b) => b.score - a.score);

  const tvBest = scoredTV[0]?.item || null;
  const movieBest = scoredMovie[0]?.item || null;
  const tvBestScore = scoredTV[0]?.score || 0;
  const movieBestScore = scoredMovie[0]?.score || 0;

  let best: any = null;
  let mediaType: 'movie' | 'tv' = 'movie';
  let movie: any = null;

  if (tvBest && movieBest) {
    // Both have matches — score-based comparison
    // For Chinese keywords: TV gets +15 score bonus to prefer series over movies
    const tvScore = tvBestScore + (isChineseKeyword ? 15 : 0);
    const movieScore = movieBestScore;
    if (tvScore > movieScore) {
      best = tvBest;
      mediaType = 'tv';
    } else if (movieScore > tvScore) {
      best = movieBest;
      mediaType = 'movie';
    } else {
      // Tie — prefer TV for Chinese keywords, otherwise pick higher vote count
      if (isChineseKeyword) {
        best = tvBest;
        mediaType = 'tv';
      } else {
        const tvVotes = tvBest.vote_count || 0;
        const movieVotes = movieBest.vote_count || 0;
        best = tvVotes >= movieVotes ? tvBest : movieBest;
        mediaType = tvVotes >= movieVotes ? 'tv' : 'movie';
      }
    }
  } else if (tvBest) {
    best = tvBest;
    mediaType = 'tv';
  } else if (movieBest) {
    best = movieBest;
    mediaType = 'movie';
  } else if (scoredTV.length > 0 && !scoredMovie.length) {
    best = scoredTV[0].item;
    mediaType = 'tv';
  } else if (scoredMovie.length > 0) {
    best = scoredMovie[0].item;
    mediaType = 'movie';
  } else if (tvResults.length > 0 && !movieResults.length) {
    best = tvResults[0];
    mediaType = 'tv';
  } else if (movieResults.length > 0) {
    best = movieResults[0];
    mediaType = 'movie';
  } else {
    return null;
  }

  let tmdbId = best.id;
  try {
    const detailUrl = `https://api.themoviedb.org/3/${mediaType}/${tmdbId}?language=zh-CN&append_to_response=credits`;
    const detailResp = await fetch(detailUrl, {
      headers: { 'Authorization': `Bearer ${tmdbToken}` },
      signal: AbortSignal.timeout(8000),
    });
    if (detailResp.ok) {
      movie = await detailResp.json() as any;
    }
  } catch {
    console.warn(`[Content] TMDB detail failed for ${mediaType} id ${tmdbId}`);
    return null;
  }

  if (!movie) return null;

  // Extract TMDB data (use title for movie, name for TV)
  const title = movie.title || movie.name || keyword;
  const rating = movie.vote_average > 0 ? String(Math.round(movie.vote_average * 10) / 10) : '';
  const ratingCount = movie.vote_count ? String(movie.vote_count) : '';
  // Use release_date for movie, first_air_date for TV
  const year = movie.release_date ? movie.release_date.substring(0, 4) : (movie.first_air_date ? movie.first_air_date.substring(0, 4) : '');
  const genres = Array.isArray(movie.genres) ? movie.genres.map((g: any) => g.name).filter(Boolean) : [];
  // Directors: tv shows have limited crew data, fall back to "creator" for TV
  const directors = Array.isArray(movie.credits?.crew)
    ? movie.credits.crew.filter((c: any) => c.job === 'Director').map((c: any) => c.name).filter(Boolean).join(' / ')
    : '';
  const actors = Array.isArray(movie.credits?.cast)
    ? movie.credits.cast.slice(0, 5).map((c: any) => c.name).filter(Boolean).join(' / ')
    : '';
  const region = Array.isArray(movie.production_countries)
    ? movie.production_countries.map((c: any) => c.name).filter(Boolean).join(' / ')
    : (Array.isArray(movie.origin_country) ? movie.origin_country.join(' / ') : '');
  const duration = mediaType === 'movie'
    ? (movie.runtime > 0 ? `${movie.runtime}分钟` : '')
    : (movie.episode_run_time && movie.episode_run_time.length > 0 ? `每集${movie.episode_run_time[0]}分钟` : '');
  const description = movie.overview ? movie.overview.substring(0, 200) : '';
  const cover = movie.poster_path ? `https://image.tmdb.org/t/p/w500${movie.poster_path}` : '';

  // TMDB detail page URL
  const tmdbUrl = `https://www.themoviedb.org/${mediaType}/${tmdbId}`;

  // Generate tags from keyword + title
  const tags = genTags({ keyword, title });

  // Build description fallback
  let desc = description;
  if (!desc) {
    const parts: string[] = [];
    if (year) parts.push(`${year}年`);
    if (genres.length > 0) parts.push(genres.slice(0, 3).join(' / '));
    if (duration) parts.push(duration);
    desc = parts.length > 0 ? parts.join(' · ') : '';
  }

  return {
    keyword,
    title,
    description: desc,
    tags,
    cover,
    source: 'tmdb',
    tmdb_url: tmdbUrl,
    rating,
    rating_count: ratingCount,
    year,
    genres,
    directors,
    actors,
    region,
    duration,
  };
}

function genTags(opts: { keyword: string; title: string }): string[] {
  const { keyword, title } = opts;
  const tags: string[] = [];
  if (keyword.length <= 8) tags.push(keyword);

  const txt = (title + ' ' + keyword).toLowerCase();
  const isDonghua = /动画|动漫/i.test(txt);
  if (isDonghua) {
    tags.push('动画'); tags.push('国漫');
  } else {
    tags.push('电影');
  }

  const genreMap: Record<string, string[]> = {
    '动画': ['动画'], '动漫': ['动漫'], '国漫': ['国漫'],
    '剧场版': ['剧场版'], '年番': ['年番'],
    '动作': ['动作'], '奇幻': ['奇幻'], '玄幻': ['玄幻'],
    '仙侠': ['仙侠'], '古装': ['古装'], '爱情': ['爱情'],
    '科幻': ['科幻'], '喜剧': ['喜剧'], '悬疑': ['悬疑'],
    '冒险': ['冒险'], '战争': ['战争'], '纪录': ['纪录片'], '真人': ['真人秀'],
  };
  for (const [key, vals] of Object.entries(genreMap)) {
    if (txt.includes(key)) {
      for (const v of vals) { if (!tags.includes(v)) tags.push(v); }
    }
  }
  return tags;
}

function safeParseTags(tagsStr: string | null | undefined): string[] {
  if (!tagsStr) return [];
  try {
    const parsed = JSON.parse(tagsStr);
    return Array.isArray(parsed) ? parsed : [];
  } catch {
    return [];
  }
}
