import boxen from 'boxen';
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';
import gradient from 'gradient-string';

import { getPackageSize } from './utils';

import type { Options as BoxenOptions } from 'boxen';

dayjs.extend(duration);

const boxenOptions: BoxenOptions = {
    padding: 0.5,
    borderColor: 'cyan',
    borderStyle: 'round',
};

// 起始时间戳经 process.env 传递。SSG 下 buildStart（vite 插件）与 buildEnd（react-router.config）
// 可能被加载为 buildReport 的不同模块实例（react-router 用独立 loader 加载 config），模块级变量不可靠；
// 而 process.env 在同一 Node 进程内必然共享，故用它跨钩子传起始时间。
const START_ENV_KEY = '__BUILD_START_TS__';

/** 打印「正在打包...」并把起始时间戳写入 process.env，供 printBuildComplete 读取。 */
export function printBuildStart(): number {
    console.log('\n' + boxen(gradient(['cyan', 'magenta']).multiline('正在打包...'), boxenOptions));
    const now = Date.now();
    process.env[START_ENV_KEY] = String(now);
    return now;
}

/** 以 Promise 封装回调式的 getPackageSize，便于在 async 钩子（如 RR buildEnd）里 await。 */
function measurePackageSize(folder: string): Promise<string | number> {
    return new Promise((resolve) => {
        getPackageSize({ folder, callback: resolve });
    });
}

/**
 * 打印「🎉 恭喜打包完成」总结框（用时 + 产物体积）。
 * @param folder 统计体积的产物目录（CSR → dist；SSG → dist/client）。
 * @param startTime 起始时间戳（毫秒）；缺省则回退到 printBuildStart 记录的模块级值。
 *
 * SSG 模式必须在 React Router 的 buildEnd 钩子里调用：client/ssr 双环境构建、prerender、
 * 删除 server 目录都在 vite closeBundle 之后发生，只有 buildEnd 晚于全部步骤，
 * 在此打印才真正是「最后一行」。
 */
export async function printBuildComplete(folder: string, startTime?: number): Promise<void> {
    const size = await measurePackageSize(folder);
    const envStart = process.env[START_ENV_KEY] ? Number(process.env[START_ENV_KEY]) : undefined;
    const start = startTime ?? envStart;
    const elapsed =
        start != null ? `总用时：${dayjs.duration(Date.now() - start).format('mm分ss秒')}\n` : '';
    console.log(
        '\n' +
            boxen(
                gradient(['cyan', 'magenta']).multiline(
                    `🎉 恭喜打包完成\n${elapsed}打包后的大小为：${size}`
                ),
                boxenOptions
            )
    );
}
