import { clickhouseService } from "./clients";
import dayjs from "dayjs";
import Art from "../models/artModel";

interface KpiData {
  dau: {
    today: number;
    trend: Array<{ date: string; dau: number }>;
  };
}

interface ArtworkStat {
  resId: string;
  name: string;
  coverImage: string | null;
  clickCount: number;
  clickRate: number;
  completionCount: number;
  completionRate: number;
}

interface ArtworkStatsResponse {
  dau_today: number;
  artworks: ArtworkStat[];
}

interface NewArtworkTabItem {
  resId: string;
  name: string;
  thumbnail: string;
  areaCount: number;
  areaCountFloor: number;
  clickCount: number;
  completionCount: number;
  tipCount: number;
  clickRate: number;
  completionRate: number;
}

interface NewArtworkTab {
  label: string;
  date: string;
  dau: number;
  artworks: NewArtworkTabItem[];
}

interface NewArtworkTabsResponse {
  tabs: NewArtworkTab[];
}

class DashboardService {
  private readonly eventsTable = "events";

  private getDayLabelByIndex(index: number): string {
    if (index === 0) return "今日";
    if (index === 1) return "昨天";
    if (index === 2) return "前天";
    return `${index}天前`;
  }

  /**
   * 获取 KPI 数据：日活用户数、日活曲线、广告收益、收益曲线
   * @param dateRange 显示过去 N 天的数据，默认 7 天
   * @returns KPI 数据对象
   */
  public async getKpi(dateRange: number = 7): Promise<KpiData> {
    try {
      const startDate = dayjs()
        .subtract(dateRange - 1, "day")
        .format("YYYY-MM-DD");
      const endDate = dayjs().format("YYYY-MM-DD");
      const today = dayjs().format("YYYY-MM-DD");

      // 查询日活用户数聚合数据
      const dauQuery = `
        SELECT 
          toDate(time) as date,
          countDistinct(uid) as dau
        FROM ${this.eventsTable}
        WHERE toDate(time) >= '${startDate}' 
          AND toDate(time) <= '${endDate}'
          AND project = 1
        GROUP BY date
        ORDER BY date
      `;

      // 获取今日具体数据
      const todayDauQuery = `
        SELECT countDistinct(uid) as dau
        FROM ${this.eventsTable}
        WHERE toDate(time) = '${today}' AND project = 1
      `;

      // 执行查询
      const [dauTrend, todayDauResult] = await Promise.all([clickhouseService.queryEvents<{ date: string; dau: number }>(dauQuery), clickhouseService.queryEvents<{ dau: number }>(todayDauQuery)]);

      const todayDau = todayDauResult?.[0]?.dau ?? 0;

      return {
        dau: {
          today: todayDau,
          trend: dauTrend.map((item) => ({
            date: item.date,
            dau: item.dau,
          })),
        },
      };
    } catch (error) {
      console.error("[DashboardService] Error fetching KPI data:", error);
      throw error;
    }
  }

  /**
   * 获取作品统计数据：点击率、完成率排行
   * @param top 返回 Top N 作品数量
   * @param sortBy 排序字段：clickRate | completionRate | clickCount | completionCount
   * @returns 作品统计数据
   */
  public async getArtworkStats(top: number = 10, sortBy: "clickRate" | "completionRate" | "clickCount" | "completionCount" = "clickCount"): Promise<ArtworkStatsResponse> {
    try {
      const today = dayjs().format("YYYY-MM-DD");

      // 查询今日日活用户
      const dauQuery = `
        SELECT countDistinct(uid) as dau
        FROM ${this.eventsTable}
        WHERE toDate(time) = '${today}' AND project = 1
      `;

      // 查询今日各作品的 color_start 和 color_done 事件计数
      const artworkQuery = `
        SELECT 
          res as resId,
          countIf(event = 'color_start') as click_count,
          countIf(event = 'color_done') as completion_count
        FROM ${this.eventsTable}
        WHERE toDate(time) = '${today}' 
          AND project = 1 
          AND res IS NOT NULL
          AND res != ''
        GROUP BY res
        ORDER BY click_count DESC
        LIMIT ${top}
      `;

      const [dauResult, artworkResults] = await Promise.all([
        clickhouseService.queryEvents<{ dau: number }>(dauQuery),
        clickhouseService.queryEvents<{ resId: string; click_count: number; completion_count: number }>(artworkQuery),
      ]);

      const dau = dauResult?.[0]?.dau ?? 0;

      const artworks: ArtworkStat[] = artworkResults.map((art) => ({
        resId: art.resId,
        name: "", // 补充：需要从 artModel 补充名称
        coverImage: null, // 补充：需要从 artModel 补充图片
        clickCount: art.click_count,
        clickRate: dau > 0 ? parseFloat((art.click_count / dau).toFixed(4)) : 0,
        completionCount: art.completion_count,
        completionRate: art.click_count > 0 ? parseFloat((art.completion_count / art.click_count).toFixed(4)) : 0,
      }));

      return {
        dau_today: dau,
        artworks,
      };
    } catch (error) {
      console.error("[DashboardService] Error fetching artwork stats:", error);
      throw error;
    }
  }

  /**
   * 获取最近 N 天上新作品分日统计（点击率/完成率）
   * @param days 天数，默认 7
   * @param topPerDay 每日最多返回作品数，默认 20
   */
  public async getNewArtworkTabs(days: number = 7, topPerDay: number = 20): Promise<NewArtworkTabsResponse> {
    try {
      const latestPublished = await Art.findOne({
        publishTime: { $exists: true, $ne: null },
        drop: { $ne: true },
      })
        .sort({ publishTime: -1 })
        .select({ publishTime: 1 })
        .lean();

      if (!latestPublished?.publishTime) {
        return { tabs: [] };
      }

      const safeDays = Math.max(1, Math.min(30, Math.floor(days || 7)));
      const latestDayStart = dayjs(latestPublished.publishTime).startOf("day");
      const rangeStart = latestDayStart.subtract(safeDays - 1, "day");
      const rangeEnd = latestDayStart.add(1, "day");

      const arts = await Art.find({
        publishTime: {
          $gte: rangeStart.toDate(),
          $lt: rangeEnd.toDate(),
        },
        drop: { $ne: true },
      })
        .select({ _id: 1, name: 1, pageId: 1, publishTime: 1, areaCount: 1, areaCountFloor: 1 })
        .lean();

      const dayKeys = Array.from({ length: safeDays }, (_, index) => latestDayStart.subtract(index, "day").format("YYYY-MM-DD"));

      const artsByDay = new Map<string, Array<{ resId: string; name: string; pageId: string; areaCount: number; areaCountFloor: number }>>();
      for (const dayKey of dayKeys) {
        artsByDay.set(dayKey, []);
      }

      const allResIds: string[] = [];
      for (const art of arts) {
        if (!art.publishTime) continue;
        const dayKey = dayjs(art.publishTime).format("YYYY-MM-DD");
        if (!artsByDay.has(dayKey)) continue;
        const resId = String(art._id);
        allResIds.push(resId);
        artsByDay.get(dayKey)?.push({
          resId,
          name: art.name || "未命名作品",
          pageId: String(art.pageId || ""),
          areaCount: Number(art.areaCount || 0),
          areaCountFloor: Number(art.areaCountFloor || 0),
        });
      }

      const uniqueResIds = Array.from(new Set(allResIds));
      const oldestDay = dayKeys[dayKeys.length - 1];
      const newestDay = dayKeys[0];

      const dauQuery = `
        SELECT
          toDate(time) AS date,
          countDistinct(uid) AS dau
        FROM ${this.eventsTable}
        WHERE project = 1
          AND toDate(time) >= '${oldestDay}'
          AND toDate(time) <= '${newestDay}'
        GROUP BY date
        ORDER BY date
      `;

      const dauRows = await clickhouseService.queryEvents<{ date: string; dau: number }>(dauQuery);
      const dauByDay = new Map<string, number>(dauRows.map((row) => [String(row.date), Number(row.dau || 0)]));

      const statsByDayAndRes = new Map<string, { clickCount: number; completionCount: number; tipCount: number }>();
      if (uniqueResIds.length > 0) {
        const inClause = uniqueResIds.map((id) => `'${id}'`).join(",");
        const artworkStatsQuery = `
          SELECT
            toDate(time) AS date,
            res AS resId,
            countIf(event = 'color_start') AS clickCount,
            countIf(event = 'color_done') AS completionCount,
            countIf(event = 'color_tip') AS tipCount
          FROM ${this.eventsTable}
          WHERE project = 1
            AND toDate(time) >= '${oldestDay}'
            AND toDate(time) <= '${newestDay}'
            AND event IN ('color_start', 'color_done', 'color_tip')
            AND res IN (${inClause})
          GROUP BY date, res
        `;

        const statRows = await clickhouseService.queryEvents<{
          date: string;
          resId: string;
          clickCount: number;
          completionCount: number;
          tipCount: number;
        }>(artworkStatsQuery);

        for (const row of statRows) {
          statsByDayAndRes.set(`${row.date}|${row.resId}`, {
            clickCount: Number(row.clickCount || 0),
            completionCount: Number(row.completionCount || 0),
            tipCount: Number(row.tipCount || 0),
          });
        }
      }

      const tabs: NewArtworkTab[] = dayKeys.map((dayKey, index) => {
        const dau = dauByDay.get(dayKey) ?? 0;
        const dayArts = (artsByDay.get(dayKey) || []).map((art) => {
          const stat = statsByDayAndRes.get(`${dayKey}|${art.resId}`) || {
            clickCount: 0,
            completionCount: 0,
            tipCount: 0,
          };

          const clickRate = dau > 0 ? stat.clickCount / dau : 0;
          const completionRate = stat.clickCount > 0 ? stat.completionCount / stat.clickCount : 0;

          return {
            resId: art.resId,
            name: art.name,
            thumbnail: `http://color2.jccytech.cn/thumbs/v2/page/320/${art.resId}.png`,
            areaCount: art.areaCount,
            areaCountFloor: art.areaCountFloor,
            clickCount: stat.clickCount,
            completionCount: stat.completionCount,
            tipCount: stat.tipCount,
            clickRate: parseFloat(clickRate.toFixed(4)),
            completionRate: parseFloat(completionRate.toFixed(4)),
          };
        });

        dayArts.sort((a, b) => b.clickCount - a.clickCount);

        return {
          label: this.getDayLabelByIndex(index),
          date: dayKey,
          dau,
          artworks: dayArts.slice(0, Math.max(1, Math.min(100, topPerDay))),
        };
      });

      return { tabs };
    } catch (error) {
      console.error("[DashboardService] Error fetching new artwork tabs:", error);
      throw error;
    }
  }
}

export default new DashboardService();
