const DAY_MS = 24 * 60 * 60 * 1000;
const DEFAULT_WINDOW_DAYS = 30;
const numberFormatter = new Intl.NumberFormat("zh-CN");

export function activityTemplateForRuntime(version, fallbackTemplate = {}) {
    const snapshot = version?.snapshot || fallbackTemplate || {};
    const runtimeFromMs = positiveNumber(version?.runtimeFromMs);
    const runtimeToMs = positiveNumber(version?.runtimeToMs);
    const plannedEndMs = positiveNumber(snapshot?.endMs);

    // 发布版本的计划窗口不会因提前停用而变化；数据中心必须以 owner 记录的实际运行窗口查询，
    // 否则历史版本会把未运行日期纳入趋势和日榜。尚在运行的版本 runtimeToMs=0，仍回退计划结束时间。
    return {
        ...snapshot,
        startMs: runtimeFromMs || positiveNumber(snapshot?.startMs),
        // 自然结束后管理员再执行停用时，runtimeToMs 可能是命令时间；统计窗口仍不能越过计划结束边界。
        endMs: runtimeToMs && plannedEndMs ? Math.min(runtimeToMs, plannedEndMs) : runtimeToMs || plannedEndMs,
    };
}

export function createActivityDataInitialRange(template, now = Date.now()) {
    const configuredStart = positiveNumber(template?.startMs) || now - (DEFAULT_WINDOW_DAYS - 1) * DAY_MS;
    const configuredEnd = positiveNumber(template?.endMs) || now;
    const rawEnd =
        now <= configuredStart
            ? Math.min(configuredEnd, configuredStart + DEFAULT_WINDOW_DAYS * DAY_MS)
            : Math.min(configuredEnd, now);
    const safeEnd = rawEnd > configuredStart ? rawEnd : Math.min(configuredEnd, configuredStart + DAY_MS);
    const endExclusive = utcDayCeil(safeEnd);
    const startInclusive = Math.max(utcDayFloor(configuredStart), endExclusive - DEFAULT_WINDOW_DAYS * DAY_MS);

    // TimeRangeFilter(withTime=false) 按浏览器本地日历渲染。把统计侧 UTC 日键投影为
    // 同名的本地日期，避免 UTC 零点在 UTC+8 显示成上午 08:00 后再被选择器截到错误日期。
    return {
        startMs: utcDayAsLocalCalendarMillis(startInclusive, false),
        endMs: utcDayAsLocalCalendarMillis(endExclusive - DAY_MS, true),
    };
}

export function canOpenActivityTemplateData(item, abilities) {
    return Boolean(abilities?.canData && Number(item?.publishedVersion || 0) > 0);
}

export function normalizeActivityDataUtcRange(range) {
    const startMs = positiveNumber(range?.startMs);
    const endMs = positiveNumber(range?.endMs);
    if (!startMs || !endMs || endMs <= startMs) return null;
    // 选择器值代表用户看到的本地日历年月日，而不是 epoch 所落的 UTC 日。
    // 上海 Jul 2 00:00 的 epoch 位于 Jul 1 UTC；必须取本地 Y/M/D 再构造 Jul 2 00:00Z。
    const startDate = new Date(startMs);
    const endDate = new Date(endMs);
    const normalized = {
        start_ms: Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()),
        end_ms: Date.UTC(endDate.getFullYear(), endDate.getMonth(), endDate.getDate() + 1),
    };
    return normalized.end_ms > normalized.start_ms ? normalized : null;
}

export function activityDailyPeriodOptions(template, now = Date.now()) {
    const startMs = utcDayFloor(positiveNumber(template?.startMs) || now);
    const configuredEnd = positiveNumber(template?.endMs) || now;
    const endMs = utcDayCeil(configuredEnd);
    const options = [];
    for (let dayMs = startMs; dayMs < endMs && options.length < 366; dayMs += DAY_MS) {
        options.push(utcDayKey(dayMs));
    }
    return options.reverse();
}

export function defaultActivityDailyPeriod(template, now = Date.now()) {
    const options = activityDailyPeriodOptions(template, now);
    const today = utcDayKey(now);
    return options.find((item) => item <= today) || options.at(-1) || today;
}

export function createActivityTemplateDataCsv(data) {
    const overview = data?.overview || {};
    const lines = [
        ["活动概览"],
        ["指标", "数值"],
        ["参与用户", overview.participants],
        ["访问人次", overview.visitCount],
        ["送礼用户", overview.giftUsers],
        ["任务用户", overview.taskUsers],
        ["送礼事件", overview.giftEventCount],
        ["礼物数量", overview.giftCount],
        ["金币金额", overview.coinAmount],
        ["任务进度", overview.taskProgress],
        ["任务完成", overview.taskCompleted],
        ["任务领奖", overview.taskClaimed],
        [],
        ["每日趋势"],
        [
            "UTC 日期",
            "参与用户",
            "访问人次",
            "送礼用户",
            "任务用户",
            "送礼事件",
            "礼物数量",
            "金币金额",
            "任务进度",
            "任务完成",
            "任务领奖",
        ],
        ...(data?.trend || []).map((item) => [
            item.statDay,
            item.participants,
            item.visitCount,
            item.giftUsers,
            item.taskUsers,
            item.giftEventCount,
            item.giftCount,
            item.coinAmount,
            item.taskProgress,
            item.taskCompleted,
            item.taskClaimed,
        ]),
        [],
        ["礼物排行"],
        ["礼物 ID", "送礼用户", "送礼事件", "礼物数量", "金币金额"],
        ...(data?.gifts || []).map((item) => [
            item.giftId,
            item.giftUsers,
            item.giftEventCount,
            item.giftCount,
            item.coinAmount,
        ]),
        [],
        ["任务排行"],
        ["任务 Key", "任务类型", "任务用户", "累计进度", "完成人次", "领奖人次"],
        ...(data?.tasks || []).map((item) => [
            item.taskKey,
            item.taskType,
            item.taskUsers,
            item.taskProgress,
            item.taskCompleted,
            item.taskClaimed,
        ]),
    ];
    return lines.map((row) => row.map(csvCell).join(",")).join("\n");
}

export function downloadActivityTemplateDataCsv(data, filename) {
    const blob = new Blob([`\uFEFF${createActivityTemplateDataCsv(data)}`], { type: "text/csv;charset=utf-8" });
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = filename;
    link.click();
    window.URL.revokeObjectURL(url);
}

export function formatActivityMetric(value) {
    return numberFormatter.format(Number(value) || 0);
}

function csvCell(value) {
    const text = value === undefined || value === null ? "" : String(value);
    return /[",\n\r]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
}

function positiveNumber(value) {
    const number = Number(value);
    return Number.isFinite(number) && number > 0 ? number : 0;
}

function utcDayFloor(value) {
    const date = new Date(value);
    return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
}

function utcDayCeil(value) {
    const floor = utcDayFloor(value);
    return floor === value ? floor : floor + DAY_MS;
}

function utcDayKey(value) {
    return new Date(utcDayFloor(value)).toISOString().slice(0, 10);
}

function utcDayAsLocalCalendarMillis(value, endOfDay) {
    const utcDate = new Date(value);
    return new Date(
        utcDate.getUTCFullYear(),
        utcDate.getUTCMonth(),
        utcDate.getUTCDate(),
        endOfDay ? 23 : 0,
        endOfDay ? 59 : 0,
        endOfDay ? 59 : 0,
        endOfDay ? 999 : 0,
    ).getTime();
}
