import { getDb } from '../database/database';
import { formatLocalDate } from '../utils/time';

export interface AdminStats {
  todaySearches: number;
  todaySaves: number;
  monthSearches: number;
  monthSaves: number;
  totalSearches: number;
  totalSaves: number;
  hotKeywords: Array<{ keyword: string; count: number }>;
  trendTrend: Array<{ date: string; searches: number; saves: number; searchDelta: number; saveDelta: number }>;
  cloudUsage: Array<{
    cloudType: string;
    nickname: string;
    storageUsed: string;
    storageTotal: string;
    isActive: boolean;
  }>;
  topIps: Array<{ ip: string; ip_location: string | null; count: number }>;
  provinceRankings: Array<{ province: string; count: number }>;
}

/**
 * Get today's date string in the configured timezone (e.g. "2026-05-04").
 * Delegates to shared formatLocalDate() in utils/time.ts.
 */
function todayLocalDate(): string {
  return formatLocalDate();
}

/**
 * Get the first day of the current month in the configured timezone.
 */
function monthStartLocalDate(): string {
  return todayLocalDate().slice(0, 7) + '-01';
}

export function getStats(trendDays: number = 7): AdminStats {
  const db = getDb();

  // Use local timezone date — NOT UTC via toISOString()
  const today = todayLocalDate();
  const monthStart = monthStartLocalDate();

  // IMPORTANT: created_at is stored as "YYYY-MM-DDTHH:mm:ss+08:00" (localTimestamp)
  // SQLite's date() function would interpret the +08:00 timezone offset and
  // convert to UTC, giving wrong date. Instead, use SUBSTR to get first 10 chars.
  const todaySearchesRow = db.prepare(
    "SELECT COUNT(*) as count FROM search_stats WHERE SUBSTR(created_at, 1, 10) = ?"
  ).get(today) as any;

  const todaySavesRow = db.prepare(
    "SELECT COUNT(*) as count FROM save_records WHERE SUBSTR(created_at, 1, 10) = ?"
  ).get(today) as any;

  const monthSearchesRow = db.prepare(
    "SELECT COUNT(*) as count FROM search_stats WHERE SUBSTR(created_at, 1, 10) >= ?"
  ).get(monthStart) as any;

  const monthSavesRow = db.prepare(
    "SELECT COUNT(*) as count FROM save_records WHERE SUBSTR(created_at, 1, 10) >= ?"
  ).get(monthStart) as any;

  // Total searches
  const totalSearchesRow = db.prepare(
    "SELECT COUNT(*) as count FROM search_stats"
  ).get() as any;

  // Total saves
  const totalSavesRow = db.prepare(
    "SELECT COUNT(*) as count FROM save_records"
  ).get() as any;

  // Hot keywords
  const hotKeywords = db.prepare(
    'SELECT keyword, search_count as count FROM hot_keywords ORDER BY search_count DESC LIMIT 20'
  ).all() as Array<{ keyword: string; count: number }>;

  // Trend data (configurable days, default 7)
  const trendLen = Math.min(Math.max(trendDays, 1), 90);
  const trendTrend: Array<{ date: string; searches: number; saves: number; searchDelta: number; saveDelta: number }> = [];
  for (let i = trendLen - 1; i >= 0; i--) {
    const d = new Date();
    const target = new Date(d.getTime() - i * 86400000);
    const dateStr = formatLocalDate(target);
    const searchRow = db.prepare(
      "SELECT COUNT(*) as count FROM search_stats WHERE SUBSTR(created_at, 1, 10) = ?"
    ).get(dateStr) as any;
    const saveRow = db.prepare(
      "SELECT COUNT(*) as count FROM save_records WHERE SUBSTR(created_at, 1, 10) = ?"
    ).get(dateStr) as any;
    trendTrend.push({
      date: dateStr,
      searches: searchRow?.count || 0,
      saves: saveRow?.count || 0,
      searchDelta: 0,
      saveDelta: 0,
    });
  }
  // Compute day-over-day delta (absolute change from previous day)
  for (let i = trendTrend.length - 1; i > 0; i--) {
    const prev = trendTrend[i - 1];
    const curr = trendTrend[i];
    curr.searchDelta = curr.searches - prev.searches;
    curr.saveDelta = curr.saves - prev.saves;
  }

  // Cloud usage
  const cloudUsage = db.prepare(
    'SELECT cloud_type as cloudType, nickname, storage_used as storageUsed, storage_total as storageTotal, is_active as isActive FROM cloud_configs ORDER BY id ASC'
  ).all() as Array<{
    cloudType: string;
    nickname: string;
    storageUsed: string;
    storageTotal: string;
    isActive: boolean;
  }>;

  // Top IPs from save_records — correctly count total per IP, then get latest location
  const topIps = db.prepare(
    `SELECT ip_address as ip, COUNT(*) as count,
       (SELECT ip_location FROM save_records s2
        WHERE s2.ip_address = s1.ip_address AND s2.ip_location IS NOT NULL AND s2.ip_location != ''
        ORDER BY s2.created_at DESC LIMIT 1) as ip_location
     FROM save_records s1
     WHERE ip_address IS NOT NULL AND ip_address != ''
     GROUP BY ip_address
     ORDER BY count DESC LIMIT 10`
  ).all() as Array<{ ip: string; ip_location: string | null; count: number }>;

  // Province rankings — extract province from ip_location (first segment)
  let provinceRankings: Array<{ province: string; count: number }> = [];
  const locRows = db.prepare(
    `SELECT ip_location FROM save_records WHERE ip_location IS NOT NULL AND ip_location != ''`
  ).all() as Array<{ ip_location: string }>;
  const provMap = new Map<string, number>();
  for (const row of locRows) {
    const parts = row.ip_location.trim().split(/\s+/);
    const province = parts[0] || '未知';
    provMap.set(province, (provMap.get(province) || 0) + 1);
  }
  provinceRankings = Array.from(provMap.entries())
    .map(([province, count]) => ({ province, count }))
    .sort((a, b) => b.count - a.count)
    .slice(0, 15);

  return {
    todaySearches: (todaySearchesRow as any)?.count || 0,
    todaySaves: (todaySavesRow as any)?.count || 0,
    monthSearches: (monthSearchesRow as any)?.count || 0,
    monthSaves: (monthSavesRow as any)?.count || 0,
    totalSearches: (totalSearchesRow as any)?.count || 0,
    totalSaves: (totalSavesRow as any)?.count || 0,
    hotKeywords,
    trendTrend,
    cloudUsage,
    topIps,
    provinceRankings,
  };
}
