/**
 * 设备指纹采集 — TypeScript 实现
 *
 * 与 device.py 逻辑一致，保留原 Python 方法不变。
 * 通过采集 UUID / CPU / HDD 三项硬件 ID，拼接后做 SHA256 得到 device_id。
 *
 * 适用环境：
 * - Node.js / Electron（Windows）：通过 child_process 执行 wmic / powershell 采集硬件 ID
 * - Node.js / Electron（macOS） ：通过 ioreg / sysctl / system_profiler 采集硬件 ID
 * - 浏览器：仅提供 SHA256 哈希工具函数，硬件采集需由上层注入
 */

import * as crypto from "node:crypto";
import { spawnSync } from "node:child_process";
import { platform } from "node:os";

// ============================================================
// 类型定义
// ============================================================

/** 可采集的硬件组件类型 */
export type Component = "uuid" | "cpu" | "hdd";

/** 查询方式 */
export type QueryMethod = "auto" | "ps" | "powershell" | "wmic";

/** 内部解析后的方法 */
type ResolvedMethod = "auto" | "powershell" | "wmic";

// ============================================================
// 查询配置（对应 Python _COMPONENT_QUERIES）
// ============================================================

interface ComponentQuery {
    powershell: string;
    wmicArgs: string[];
    headerTokens: string[];
}

const COMPONENT_QUERIES: Record<Component, ComponentQuery> = {
    uuid: {
        powershell:
            "Get-CimInstance -Class Win32_ComputerSystemProduct | " +
            "Select-Object -ExpandProperty UUID",
        wmicArgs: ["wmic", "csproduct", "get", "uuid"],
        headerTokens: ["uuid"],
    },
    cpu: {
        powershell:
            "Get-CimInstance -Class Win32_Processor | " +
            "Select-Object -ExpandProperty ProcessorId",
        wmicArgs: ["wmic", "cpu", "get", "processorid"],
        headerTokens: ["processorid"],
    },
    hdd: {
        powershell:
            "Get-CimInstance -Class Win32_DiskDrive | " +
            "Select-Object -First 1 -ExpandProperty SerialNumber",
        wmicArgs: ["wmic", "diskdrive", "get", "serialnumber"],
        headerTokens: ["serialnumber"],
    },
};

// ============================================================
// Mac 查询配置
// ============================================================

interface MacComponentQuery {
    command: string[];
    /** 从命令 stdout 中提取目标值 */
    extract: (output: string) => string;
}

const MAC_COMPONENT_QUERIES: Record<Component, MacComponentQuery> = {
    uuid: {
        command: ['ioreg', '-d2', '-c', 'IOPlatformExpertDevice'],
        extract: (output: string): string => {
            const m = output.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
            return m?.[1] ?? '';
        },
    },
    cpu: {
        command: ['sysctl', '-n', 'hw.model'],
        extract: (output: string): string => output.trim(),
    },
    hdd: {
        command: ['system_profiler', 'SPNVMeDataType'],
        extract: (output: string): string => {
            const m = output.match(/Serial Number:\s*(.+)/i);
            return m?.[1]?.trim() ?? '';
        },
    },
};

// ============================================================
// 工具函数
// ============================================================

/** 对应 Python: _normalize_identifier(value) -> str */
function normalizeIdentifier(value: string): string {
    if (!value) return "";
    return value.replace(/[^A-Za-z0-9]/g, "").toUpperCase();
}

/** 对应 Python: _first_value_from_output(raw_output, header_tokens) -> str */
function firstValueFromOutput(
    rawOutput: string,
    headerTokens: readonly string[],
): string {
    if (!rawOutput) return "";
    const headers = new Set(headerTokens.map((t) => t.toLowerCase()));
    for (const line of rawOutput.split(/\r?\n/)) {
        const candidate = line.trim();
        if (!candidate) continue;
        if (headers.has(candidate.toLowerCase())) continue;
        return candidate;
    }
    return "";
}

/** 对应 Python: _resolve_method(method) -> _ResolvedMethod */
function resolveMethod(method: QueryMethod): ResolvedMethod {
    if (method === "ps") return "powershell";
    return method;
}

/** 计算 SHA256 哈希（hex 大写），对应 Python hashlib.sha256(...).hexdigest().upper() */
function sha256HexUpper(input: string): string {
    return crypto.createHash("sha256").update(input, "utf-8").digest("hex").toUpperCase();
}

// ============================================================
// 环境检测
// ============================================================

function isWindows(): boolean {
    return platform() === "win32";
}

function isMacOS(): boolean {
    return platform() === "darwin";
}

function isWmicAvailable(): boolean {
    if (!isWindows()) return false;
    const result = spawnSync("where", ["wmic"], {
        timeout: 3000,
        stdio: "ignore",
        windowsHide: true,
    });
    return result.status === 0;
}

function isPowershellAvailable(): boolean {
    if (!isWindows()) return false;
    const result = spawnSync("where", ["powershell"], {
        timeout: 3000,
        stdio: "ignore",
        windowsHide: true,
    });
    return result.status === 0;
}

// ============================================================
// 进程执行
// ============================================================

/**
 * 执行命令并返回 stdout（去除首尾空白）。
 * 对应 Python: _run_process(args, timeout=5.0) -> str
 */
function runProcess(args: string[], timeoutSec: number = 5.0): string {
    const command = args[0];
    const cmdArgs = args.slice(1);
    try {
        const result = spawnSync(command, cmdArgs, {
            timeout: Math.round(timeoutSec * 1000),
            encoding: "utf-8",
            stdio: ["ignore", "pipe", "pipe"],
            windowsHide: true, // 对应 Python STARTF_USESHOWWINDOW
        });
        if (result.status !== 0) return "";
        return (result.stdout ?? "").trim();
    } catch {
        return "";
    }
}

/** 对应 Python: _run_powershell(command) -> str */
function runPowershell(command: string): string {
    if (!isPowershellAvailable()) return "";
    const args = ["powershell", "-NoProfile", "-NonInteractive", "-Command", command];
    return runProcess(args);
}

/** 对应 Python: _run_wmic(args) -> str */
function runWmic(args: readonly string[]): string {
    if (!isWmicAvailable()) return "";
    return runProcess([...args]);
}

/** 执行 Mac 命令并返回 stdout（去除首尾空白） */
function runMacCommand(args: string[], timeoutSec: number = 5.0): string {
    if (!isMacOS()) return "";
    return runProcess(args, timeoutSec);
}

/**
 * Mac HDD 标识采集 — 三级回退保证覆盖率
 * ① NVMe 磁盘序列号（Apple Silicon / 新款 Intel）
 * ② SATA 磁盘序列号（老款 Intel Mac）
 * ③ 系统序列号（最终兜底，仍唯一）
 */
function getMacHddValue(): string {
    // ① 尝试 NVMe
    let output = runMacCommand(['system_profiler', 'SPNVMeDataType']);
    let m = output.match(/Serial Number:\s*(.+)/i);
    if (m?.[1]?.trim()) return m[1].trim();

    // ② 回退：SATA
    output = runMacCommand(['system_profiler', 'SPSerialATADataType']);
    m = output.match(/Serial Number:\s*(.+)/i);
    if (m?.[1]?.trim()) return m[1].trim();

    // ③ 最终兜底：系统序列号
    output = runMacCommand(['system_profiler', 'SPHardwareDataType']);
    m = output.match(/Serial Number[^:]*:\s*(.+)/i);
    return m?.[1]?.trim() ?? '';
}

// ============================================================
// DeviceFingerprint 类
// ============================================================

export class DeviceFingerprint {
    // private wmicAvailableCache: boolean | null = null;
    // private powershellAvailableCache: boolean | null = null;

    // ---------- 组件 ID 查询 ----------

    /**
     * 查询单个硬件组件 ID。
     * 对应 Python: get_component_id(component, method="auto") -> str
     */
    getComponentId(component: Component, method: QueryMethod = "auto"): string {
        // Mac 路径：ioreg / sysctl / system_profiler
        if (isMacOS()) {
            if (component === 'hdd') {
                return normalizeIdentifier(getMacHddValue());
            }
            const macQuery = MAC_COMPONENT_QUERIES[component];
            if (!macQuery) return '';
            const output = runMacCommand(macQuery.command);
            return normalizeIdentifier(macQuery.extract(output));
        }

        // Windows 路径：wmic / powershell
        const query = COMPONENT_QUERIES[component];
        if (!query) return "";

        const resolvedMethod = resolveMethod(method);

        const readViaPowershell = (): string => {
            const rawOutput = runPowershell(query.powershell);
            return firstValueFromOutput(rawOutput, query.headerTokens);
        };

        const readViaWmic = (): string => {
            const rawOutput = runWmic(query.wmicArgs);
            return firstValueFromOutput(rawOutput, query.headerTokens);
        };

        let rawValue = "";
        if (resolvedMethod === "powershell") {
            rawValue = readViaPowershell();
        } else if (resolvedMethod === "wmic") {
            rawValue = readViaWmic();
            if (!rawValue) {
                rawValue = readViaPowershell();
            }
        } else {
            // auto: wmic 优先，回退 powershell
            rawValue = readViaWmic() || readViaPowershell();
        }

        return normalizeIdentifier(rawValue);
    }

    /**
     * 查询单个硬件组件（别名）。
     * 对应 Python: get_component(component_type, method="auto") -> str
     */
    getComponent(component: Component, method: QueryMethod = "auto"): string {
        return this.getComponentId(component, method);
    }

    // ---------- 机器指纹 ----------

    /**
     * 生成设备指纹 SHA256。
     * 采集 UUID + HDD + CPU，拼接后做 SHA256 哈希。
     * 对应 Python: fingerprint_sha256(method="auto") -> str | None
     */
    fingerprintSha256(method: QueryMethod = "auto"): string | null {
        // Mac 路径：ioreg / sysctl / system_profiler
        if (isMacOS()) {
            const uuidId = this.getComponentId("uuid", method);
            const diskId = this.getComponentId("hdd", method);
            const cpuId = this.getComponentId("cpu", method);

            if (!uuidId && !diskId && !cpuId) {
                return null;
            }

            const combined = `${uuidId}|${diskId}|${cpuId}`;
            const normalized = normalizeIdentifier(combined);
            return sha256HexUpper(normalized);
        }

        // Windows 路径：wmic / powershell
        const resolvedMethod = resolveMethod(method);
        const wmicOk = isWmicAvailable();
        const psOk = isPowershellAvailable();

        if (resolvedMethod === "powershell") {
            if (!psOk) return null;
        } else {
            if (!wmicOk && !psOk) return null;
        }

        const uuidId = this.getComponentId("uuid", method);
        const diskId = this.getComponentId("hdd", method);
        const cpuId = this.getComponentId("cpu", method);

        if (!uuidId && !diskId && !cpuId) {
            return null;
        }

        const combined = `${uuidId}|${diskId}|${cpuId}`;
        const normalized = normalizeIdentifier(combined);
        return sha256HexUpper(normalized);
    }

    /**
     * 获取机器码（指纹的别名）。
     * 对应 Python: get_machine_code(method="auto") -> str | None
     */
    getMachineCode(method: QueryMethod = "auto"): string | null {
        return this.fingerprintSha256(method);
    }
}

// ============================================================
// 便捷函数（无需实例化）
// ============================================================

const defaultFingerprint = new DeviceFingerprint();

/** 获取机器码（单例便捷调用） */
export function getMachineCode(method: QueryMethod = "auto"): string | null {
    return defaultFingerprint.getMachineCode(method);
}

/** 获取设备指纹 SHA256（单例便捷调用） */
export function fingerprintSha256(method: QueryMethod = "auto"): string | null {
    return defaultFingerprint.fingerprintSha256(method);
}

/** 查询单个硬件组件 ID（单例便捷调用） */
export function getComponentId(component: Component, method: QueryMethod = "auto"): string {
    return defaultFingerprint.getComponentId(component, method);
}
