// 自动更新 — HeiXiuProvider + electron-updater 增量下载
// 流程图：调用自有 API → 获取版本信息 → electron-updater 差分下载 → SHA512 校验 → 安装

import {app, BrowserWindow, ipcMain} from 'electron';
import {createHash} from 'node:crypto';
import {URL} from 'node:url';

import {
    NsisUpdater,
    MacUpdater,
    AppImageUpdater,
    Provider,
} from 'electron-updater';
import type {ProviderRuntimeOptions} from 'electron-updater/out/providers/Provider';
import type {UpdateInfo, UpdateFileInfo} from 'builder-util-runtime';
import type {ResolvedUpdateFileInfo} from 'electron-updater/out/types';

import type {UpdateCheckResult} from '../../shared/types';
import {APP_VERSION} from '../../shared/constants/version';
import {logger} from './logger';
import {netRequest} from './net-request';

// ---------- 构建时注入的渠道信息 ----------

/** 构建渠道（由 build.mjs 通过 VITE_BUILD_CHANNEL 注入，Vite 编译时内联） */
const BUILD_CHANNEL: string =
    (typeof import.meta !== 'undefined' && (import.meta as Record<string, unknown>).env
        ? ((import.meta as Record<string, unknown>).env as Record<string, string>).VITE_BUILD_CHANNEL
        : undefined)
    || process.env.VITE_BUILD_CHANNEL
    || 'stable';

/** 构建版本类型（由 build.mjs 通过 VITE_BUILD_EDITION 注入） */
const BUILD_EDITION: string =
    (typeof import.meta !== 'undefined' && (import.meta as Record<string, unknown>).env
        ? ((import.meta as Record<string, unknown>).env as Record<string, string>).VITE_BUILD_EDITION
        : undefined)
    || process.env.VITE_BUILD_EDITION
    || 'personal';

// ---------- 设备指纹（稳定的机器标识，用于灰度分组）----------

let _deviceFingerprint: string | null = null;

/** 获取设备指纹（基于机器特定信息的 SHA-256 前 16 位） */
function getDeviceFingerprint(): string {
    if (_deviceFingerprint) return _deviceFingerprint;

    try {
        const parts = [
            process.platform,
            process.arch,
            app.getPath('home'),
        ];
        _deviceFingerprint = createHash('sha256')
            .update(parts.join('|'))
            .digest('hex')
            .slice(0, 16);
    } catch {
        _deviceFingerprint = 'unknown-device';
    }

    return _deviceFingerprint;
}

// ---------- IPC 通道（对渲染进程暴露，与旧版兼容）----------

export const UPDATE_CHANNELS = {
    UPDATE_AVAILABLE: 'update-available',
    UPDATE_PROGRESS: 'update-progress',
    UPDATE_DOWNLOADED: 'update-downloaded',
    UPDATE_ERROR: 'update-error',
    UPDATE_NOT_AVAILABLE: 'update-not-available',
    INSTALL_UPDATE: 'install-update',
    CHECK_FOR_UPDATE: 'check-for-update',
    DOWNLOAD_UPDATE: 'download-update',
} as const;

// ---------- 配置 ----------

function getApiBaseUrl(): string {
    const url = (process.env.UPDATE_API_URL || 'https://www.heixiu.com').trim();
    console.log(`[updater] UPDATE_API_URL=${process.env.UPDATE_API_URL} → 使用: ${url}`);
    return url;
}

// ============================================================
// 自定义 Provider
// ============================================================

class HeiXiuProvider extends Provider<UpdateInfo> {
    private apiBaseUrl: string;
    /** 短时缓存：避免 checkForUpdates 预检 + electron-updater 内部调用导致两次 API 请求 */
    private _cachedResult: { data: UpdateInfo; ts: number } | null = null;

    constructor(runtimeOptions: ProviderRuntimeOptions) {
        super(runtimeOptions);
        this.apiBaseUrl = getApiBaseUrl();
    }

    /**
     * 调用自有版本检查 API，返回 electron-updater 格式的 UpdateInfo。
     * blockMapSize > 0 时 electron-updater 自动启用差分下载。
     * 无更新时返回当前版本号（APP_VERSION）。
     */
    async getLatestVersion(): Promise<UpdateInfo> {
        // 短时缓存（500ms）：预检和 electron-updater 内部调用共享同一结果
        if (this._cachedResult && Date.now() - this._cachedResult.ts < 500) {
            return this._cachedResult.data;
        }
        const data = await this._doGetLatestVersion();
        this._cachedResult = { data, ts: Date.now() };
        return data;
    }

    private async _doGetLatestVersion(): Promise<UpdateInfo> {
        const {data} = await netRequest.get<{ code: number; data?: UpdateCheckResult } & UpdateCheckResult>(
            '/api/v1/update/check',
            {
                baseURL: this.apiBaseUrl,
                params: {
                    platform: process.platform,
                    version: APP_VERSION,
                    channel: BUILD_CHANNEL,
                    edition: BUILD_EDITION,
                    deviceFingerprint: getDeviceFingerprint(),
                },
            },
        );

        // 兼容两种 API 响应格式
        const result: UpdateCheckResult =
            (data as { data?: UpdateCheckResult }).data ?? (data as UpdateCheckResult);

        // 无更新 → 返回当前版本号
        if (!result.hasUpdate) {
            return {
                version: APP_VERSION,
                files: [],
                path: '',
                sha512: '',
                releaseDate: new Date().toISOString(),
            };
        }

        const file: UpdateFileInfo = {
            url: result.downloadUrl,
            sha512: result.sha512,
            size: result.fileSize,
        };

        // 后端 API 返回 blockMapSize 时启用增量更新
        if (result.blockMapSize) {
            file.blockMapSize = result.blockMapSize;
        }

        logger.info('updater', 'Provider 获取到新版本', {
            latestVersion: result.latestVersion,
            hasBlockmap: file.blockMapSize != null,
        });

        return {
            version: result.latestVersion,
            files: [file],
            path: result.downloadUrl,
            sha512: result.sha512,
            releaseDate: result.releaseDate,
            releaseNotes: result.changelog,
        };
    }

    /**
     * 将 UpdateInfo 中的相对路径解析为完整的下载 URL。
     * electron-updater 在下载前调用此方法。
     */
    resolveFiles(updateInfo: UpdateInfo): Array<ResolvedUpdateFileInfo> {
        return updateInfo.files.map((f) => {
            // 使用 downloadUrl 作为 base URL 来解析文件路径
            const baseUrl = new URL(updateInfo.path);
            const fileUrl = new URL(f.url, baseUrl.origin);
            return {
                url: fileUrl,
                info: f,
            };
        });
    }
}

// ============================================================
// 平台特定 Updater（注入自定义 Provider）
// ============================================================

/**
 * 覆盖 getUpdateInfoAndProvider() 以注入 HeiXiuProvider。
 * 其他行为（NSIS 安装、签名校验等）完全由父类处理。
 */
class HeiXiuNsisUpdater extends NsisUpdater {
    private heiXiuProvider: HeiXiuProvider;

    constructor(heiXiuProvider: HeiXiuProvider) {
        // 传 undefined 跳过内置 Provider 创建，由我们自己注入
        super(undefined);
        this.heiXiuProvider = heiXiuProvider;
        this.autoDownload = false; // 由我们手动控制流程，保持 IPC 兼容
        this.autoInstallOnAppQuit = false;
        this.forceDevUpdateConfig = true; // 绕过 electron-updater 的 dev 模式检查
    }

    /** @internal — 注入自定义 Provider */
    protected override async getUpdateInfoAndProvider(): Promise<{
        info: UpdateInfo;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        provider: Provider<any>;
    }> {
        const info = await this.heiXiuProvider.getLatestVersion();
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return {info, provider: this.heiXiuProvider as Provider<any>};
    }
}

class HeiXiuMacUpdater extends MacUpdater {
    private heiXiuProvider: HeiXiuProvider;

    constructor(heiXiuProvider: HeiXiuProvider) {
        super(undefined);
        this.heiXiuProvider = heiXiuProvider;
        this.autoDownload = false;
        this.autoInstallOnAppQuit = false;
    }

    protected override async getUpdateInfoAndProvider(): Promise<{
        info: UpdateInfo;

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        provider: Provider<any>;
    }> {
        const info = await this.heiXiuProvider.getLatestVersion();

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return {info, provider: this.heiXiuProvider as Provider<any>};
    }
}

class HeiXiuAppImageUpdater extends AppImageUpdater {
    private heiXiuProvider: HeiXiuProvider;

    constructor(heiXiuProvider: HeiXiuProvider) {
        super(null);
        this.heiXiuProvider = heiXiuProvider;
        this.autoDownload = false;
        this.autoInstallOnAppQuit = false;
    }

    protected override async getUpdateInfoAndProvider(): Promise<{
        info: UpdateInfo;

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        provider: Provider<any>;
    }> {
        const info = await this.heiXiuProvider.getLatestVersion();

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return {info, provider: this.heiXiuProvider as Provider<any>};
    }
}

/** 工厂：按平台创建对应的 Updater 实例 */
function createPlatformUpdater(provider: HeiXiuProvider) {
    switch (process.platform) {
        case 'win32':
            return new HeiXiuNsisUpdater(provider);
        case 'darwin':
            return new HeiXiuMacUpdater(provider);
        default:
            return new HeiXiuAppImageUpdater(provider);
    }
}

// ---------- 状态 ----------

let updateWindow: BrowserWindow | null = null;
let provider: HeiXiuProvider | null = null;
let platformUpdater: NsisUpdater | MacUpdater | AppImageUpdater | null = null;

// ============================================================
// 初始化
// ============================================================

export function initUpdater(mainWindow: BrowserWindow): void {
    updateWindow = mainWindow;

    console.log('[updater] initUpdater 被调用');
    console.log(`[updater]   API URL:    ${getApiBaseUrl()}`);
    console.log(`[updater]   渠道:       ${BUILD_CHANNEL}`);
    console.log(`[updater]   版本类型:   ${BUILD_EDITION}`);
    console.log(`[updater]   当前版本:   ${APP_VERSION}`);
    console.log(`[updater]   设备指纹:   ${getDeviceFingerprint()}`);

    // if (import.meta.env.DEV) {
    //    logger.info('updater', '开发模式，跳过自动检查更新', { apiUrl: getApiBaseUrl() });
    //    return;
    // }

    // 创建自定义 Provider
    provider = new HeiXiuProvider({
        isUseMultipleRangeRequest: true,
        platform: process.platform as ProviderRuntimeOptions['platform'],
        executor: null as unknown as ProviderRuntimeOptions['executor'],
    });

    // 创建平台 Updater
    platformUpdater = createPlatformUpdater(provider);

    // 将 electron-updater 事件桥接到现有 IPC 通道
    platformUpdater.on('checking-for-update', () => {
        logger.debug('updater', '正在检查更新');
    });

    platformUpdater.on('update-available', (info: UpdateInfo) => {
        // releaseNotes 可能是 string | ReleaseNoteInfo[] | null，统一转为 string
        let notes = '';
        if (typeof info.releaseNotes === 'string') {
            notes = info.releaseNotes;
        } else if (Array.isArray(info.releaseNotes)) {
            notes = info.releaseNotes.map((n) => n.note).filter(Boolean).join('\n');
        }

        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_AVAILABLE, {
            version: info.version,
            releaseDate: info.releaseDate,
            releaseNotes: notes,
            forceUpdate: false,
        });
        logger.info('updater', '发现新版本', {
            version: info.version,
            releaseNotes: notes ? `${notes.slice(0, 50)}...` : '(空)',
        });
    });

    platformUpdater.on('update-not-available', (info: UpdateInfo) => {
        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_NOT_AVAILABLE);
        logger.info('updater', '当前已是最新版本', {currentVersion: info.version});
    });

    platformUpdater.on('download-progress', (progress: {
        percent: number;
        bytesPerSecond: number;
        transferred: number;
        total: number
    }) => {
        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_PROGRESS, {
            percent: Math.round(progress.percent),
            bytesPerSecond: progress.bytesPerSecond,
            transferred: progress.transferred,
            total: progress.total,
        });
    });

    platformUpdater.on('update-downloaded', () => {
        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_DOWNLOADED);
        logger.info('updater', '更新已下载完成');
    });

    platformUpdater.on('error', (error: Error) => {
        logger.error('updater', '更新流程出错', error);
        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_ERROR, {
            message: error.message || '更新失败',
        });
    });

    // 启动 5 秒后静默检查
    setTimeout(() => {
        checkForUpdates();
    }, 5000);
}

// ============================================================
// 操作方法
// ============================================================

let updateChecked = false;

/** 静默检查更新（自动下载） */
export async function checkForUpdates(): Promise<void> {
    if (updateChecked) {
        logger.debug('updater', '已检查过更新，跳过');
        return;
    }

    if (!platformUpdater || !provider) return;

    try {
        updateChecked = true;

        // ① 先自行检查有无更新（不经过 electron-updater）
        const info = await provider.getLatestVersion();
        if (info.version === APP_VERSION) {
            // 无更新 → 直接通知 UI，不触发 electron-updater 的任何事件
            updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_NOT_AVAILABLE);
            logger.debug('updater', '当前已是最新版本', {version: APP_VERSION});
            return;
        }

        // ② 有新版本 → 交给 electron-updater 触发 'update-available' 事件（不自动下载）
        await platformUpdater.checkForUpdates();
    } catch (error) {
        updateChecked = false;
        logger.error('updater', '更新流程失败', error as Error, {apiUrl: getApiBaseUrl()});
        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_ERROR, {
            message: (error as Error).message || '更新检查失败',
        });
    }
}

/** 手动检查更新（用户点击触发） */
export async function checkForUpdatesManual(): Promise<void> {
    if (!platformUpdater || !provider) return;

    try {
        updateChecked = false;

        // ① 先自行检查有无更新
        const info = await provider.getLatestVersion();
        if (info.version === APP_VERSION) {
            // 无更新 → 直接通知 UI
            updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_NOT_AVAILABLE);
            logger.debug('updater', '手动检查：当前已是最新版本', {version: APP_VERSION});
            return;
        }

        // ② 有新版本 → 交给 electron-updater 触发 'update-available' 事件（不自动下载）
        await platformUpdater.checkForUpdates();
    } catch (error) {
        logger.error('updater', '手动更新失败', error as Error);
        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_ERROR, {
            message: (error as Error).message || '检查更新失败',
        });
    }
}

/** 用户确认后开始下载更新 */
export async function downloadUpdate(): Promise<void> {
    if (!platformUpdater) {
        logger.warn('updater', 'downloadUpdate: Updater 未初始化');
        return;
    }
    try {
        await platformUpdater.downloadUpdate();
    } catch (error) {
        logger.error('updater', '下载更新失败', error as Error);
        updateWindow?.webContents.send(UPDATE_CHANNELS.UPDATE_ERROR, {
            message: (error as Error).message || '下载更新失败',
        });
    }
}

/** 安装已下载的更新并退出应用 */
export function installUpdateNow(): void {
    if (!platformUpdater) {
        logger.warn('updater', 'Updater 未初始化');
        return;
    }

    logger.info('updater', '开始安装更新并退出应用');
    setImmediate(() => {
        platformUpdater!.quitAndInstall(false, true);
    });
}

// ============================================================
// IPC 注册
// ============================================================

export function registerUpdateIpcHandlers(): void {
    ipcMain.handle(UPDATE_CHANNELS.CHECK_FOR_UPDATE, async () => {
        await checkForUpdatesManual();
    });

    ipcMain.handle(UPDATE_CHANNELS.DOWNLOAD_UPDATE, async () => {
        await downloadUpdate();
    });

    ipcMain.on(UPDATE_CHANNELS.INSTALL_UPDATE, () => {
        installUpdateNow();
    });
}
