#!/usr/bin/env node
/**
 * OEM配置自动应用脚本
 * 使用方法：node apply-oem.cjs
 */

// 强制使用 UTF-8 输出（解决 Windows 控制台中文乱码）
if (process.platform === 'win32') {
    try { require('child_process').execSync('chcp 65001', { stdio: 'ignore' }); } catch (e) { }
}

const fs = require('fs');
const path = require('path');
const { syncVersions } = require('./scripts/sync-version.cjs');

// 读取OEM配置
const oemConfig = require('./oem-config.cjs');

function findFirstLevelDirsWith(relativeFile) {
    const dirs = ['.'];
    for (const entry of fs.readdirSync(__dirname, { withFileTypes: true })) {
        if (!entry.isDirectory()) continue;
        if (entry.name === 'node_modules' || entry.name === 'tmp' || entry.name.startsWith('.')) continue;

        const candidate = path.join(__dirname, entry.name, relativeFile);
        if (fs.existsSync(candidate)) {
            dirs.push(entry.name);
        }
    }
    return dirs;
}

console.log('========================================');
console.log('OEM Config Apply Start');
console.log('Brand:', oemConfig.brandName);
console.log('Slogan:', oemConfig.brandSlogan);
console.log('API:', oemConfig.apiBaseUrl);
console.log('========================================\n');

const configuredVersion = oemConfig.appVersion || process.env.APP_VERSION || process.env.OEM_VERSION;
if (configuredVersion) {
    const result = syncVersions(configuredVersion, { silent: true });
    console.log('[OK] Synced app package versions:', result.version, '(' + result.packageCount + ' apps)');
    if (result.changed.length > 0) {
        result.changed.forEach(file => console.log('  [VERSION] ' + file));
    }
    console.log('');
}

// 通用替换函数（带调试信息）
function replaceInFile(filePath, replacements) {
    if (!fs.existsSync(filePath)) return false;
    let content = fs.readFileSync(filePath, 'utf8');
    let changed = false;
    for (const [pattern, replacement] of replacements) {
        const before = content;
        content = content.replace(pattern, replacement);
        if (content !== before) {
            changed = true;
            console.log('  [CHANGED] pattern matched: ' + pattern);
        } else {
            console.log('  [SKIP] pattern not matched: ' + pattern);
        }
    }
    if (changed) {
        fs.writeFileSync(filePath, content, 'utf8');
    }
    return changed;
}

function quoted(value) {
    return JSON.stringify(String(value || ''));
}

function templateQuoted(value) {
    return '`' + String(value || '').replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${') + '`';
}

// ========== 1. 更新所有 config.ts 文件 ==========
const configDirs = findFirstLevelDirsWith(path.join('src', 'config.ts'))
    .map(dir => dir === '.' ? 'src' : path.join(dir, 'src'));

const apiUrl = oemConfig.apiBaseUrl || '';
const brandName = oemConfig.brandName || '';
const brandSlogan = oemConfig.brandSlogan || '';

let configUpdated = 0;
configDirs.forEach(dir => {
    const configPath = path.join(__dirname, dir, 'config.ts');
    if (!fs.existsSync(configPath)) return;

    console.log('\nProcessing: ' + configPath);

    const replacements = [
        // name: "任意内容"  →  name: "新品牌名"
        [/name:\s*"[^"]*"/, 'name: ' + quoted(brandName)],
        // title: "任意内容"  →  title: "新品牌名"
        [/title:\s*"[^"]*"/, 'title: ' + quoted(brandName)],
        // slogan: "任意内容"  →  slogan: "新标语"
        [/slogan:\s*"[^"]*"/, 'slogan: ' + quoted(brandSlogan)],
    ];

    if (apiUrl) {
        // apiBaseUrl: `任意内容`  →  apiBaseUrl: `新地址`（反引号格式）
        replacements.push([/apiBaseUrl:\s*`[^`]*`/, 'apiBaseUrl: ' + templateQuoted(apiUrl)]);
        // apiBaseUrl: "任意内容"  →  apiBaseUrl: "新地址"（双引号格式兜底）
        replacements.push([/apiBaseUrl:\s*"[^"]*"/, 'apiBaseUrl: ' + quoted(apiUrl)]);
    }

    const ok = replaceInFile(configPath, replacements);
    if (ok) {
        configUpdated++;
        console.log('  [OK] Updated: ' + configPath);
    } else {
        console.log('  [WARN] Nothing changed in: ' + configPath);
    }
});

console.log('\nTotal config.ts files updated: ' + configUpdated + '\n');

// ========== 1.5 更新 electron 端的认证服务器地址 ==========
if (apiUrl) {
    const authConfigPath = path.join(__dirname, 'electron/mapi/auth/config.ts');
    // 从 apiBaseUrl 提取基础地址（去掉末尾的 /api）
    const baseServerUrl = apiUrl.replace(/\/api\/?$/, '');

    console.log('Processing auth config: ' + authConfigPath);
    const authConfigContent = fs.existsSync(authConfigPath) ? fs.readFileSync(authConfigPath, 'utf8') : '';
    if (authConfigContent.includes('AppConfig.apiBaseUrl')) {
        console.log('  [OK] AUTH_SERVER_URL is derived from AppConfig.apiBaseUrl -> ' + baseServerUrl + '\n');
    } else {
        const ok = replaceInFile(authConfigPath, [
            [/AUTH_SERVER_URL\s*=\s*process\.env\.AUTH_SERVER_URL\s*\|\|\s*'[^']*'/, 'AUTH_SERVER_URL = process.env.AUTH_SERVER_URL || ' + quoted(baseServerUrl)],
            [/AUTH_SERVER_URL\s*=\s*process\.env\.AUTH_SERVER_URL\s*\|\|\s*"[^"]*"/, 'AUTH_SERVER_URL = process.env.AUTH_SERVER_URL || ' + quoted(baseServerUrl)],
        ]);
        if (ok) {
            console.log('  [OK] AUTH_SERVER_URL -> ' + baseServerUrl + '\n');
        } else {
            console.log('  [WARN] AUTH_SERVER_URL pattern not matched\n');
        }
    }
}

// ========== 2. 复制二维码图片 ==========
const qrcodeDirs = findFirstLevelDirsWith(path.join('src', 'assets', 'image'))
    .map(dir => dir === '.' ? path.join('src', 'assets', 'image') : path.join(dir, 'src', 'assets', 'image'));

const sourceQrcode = path.join(__dirname, oemConfig.qrcodePath);
if (fs.existsSync(sourceQrcode)) {
    let qrcodeUpdated = 0;
    qrcodeDirs.forEach(dir => {
        const targetDir = path.join(__dirname, dir);
        if (fs.existsSync(targetDir)) {
            const targetPath = path.join(targetDir, 'qrcode-wish.png');
            fs.copyFileSync(sourceQrcode, targetPath);
            qrcodeUpdated++;
            console.log('[OK] Copied qrcode to: ' + targetPath);
        }
    });
    console.log('\nTotal qrcode files copied: ' + qrcodeUpdated + '\n');
} else {
    console.error('[WARN] Qrcode file not found: ' + sourceQrcode);
}

// ========== 3. 复制 LOGO 图片 ==========
const logoDirs = [
    { src: 'public', file: 'logo.svg' },
    { src: 'electron/resources/build', file: 'logo.png' },
];
const sourceLogo = oemConfig.logoPath ? path.join(__dirname, oemConfig.logoPath) : null;
if (sourceLogo && fs.existsSync(sourceLogo)) {
    const publicDir = path.join(__dirname, 'public');
    if (fs.existsSync(publicDir)) {
        fs.copyFileSync(sourceLogo, path.join(publicDir, 'logo.png'));
        console.log('[OK] Copied logo.png to public/');
    }
    const buildDir = path.join(__dirname, 'electron/resources/build');
    if (fs.existsSync(buildDir)) {
        fs.copyFileSync(sourceLogo, path.join(buildDir, 'logo.png'));
        console.log('[OK] Copied logo.png to electron/resources/build/');
    }
    const allPublicDirs = fs.readdirSync(__dirname).filter(d => {
        const sub = path.join(__dirname, d, 'public');
        return fs.existsSync(sub) && d !== 'node_modules';
    });
    allPublicDirs.forEach(d => {
        const target = path.join(__dirname, d, 'public', 'logo.png');
        try { fs.copyFileSync(sourceLogo, target); console.log('[OK] Copied logo to ' + d + '/public/'); } catch(e) {}
    });
    console.log('');
} else {
    console.log('[INFO] No logoPath configured or file not found, skipping logo copy\n');
}

// ========== 3.5 复制图标（ICO/ICNS） ==========
const sourceIcon = oemConfig.iconPath ? path.join(__dirname, oemConfig.iconPath) : null;
if (sourceIcon && fs.existsSync(sourceIcon)) {
    const buildDir = path.join(__dirname, 'electron/resources/build');
    if (fs.existsSync(buildDir)) {
        const sharp = require('sharp');
        const iconBuf = fs.readFileSync(sourceIcon);

        (async () => {
            try {
                await sharp(iconBuf).resize(256, 256).png().toFile(path.join(buildDir, 'logo.png'));
                console.log('[OK] Generated logo.png (256x256)');

                const png256 = await sharp(iconBuf).resize(256, 256).png().toBuffer();
                const png128 = await sharp(iconBuf).resize(128, 128).png().toBuffer();
                const png64 = await sharp(iconBuf).resize(64, 64).png().toBuffer();
                const png48 = await sharp(iconBuf).resize(48, 48).png().toBuffer();
                const png32 = await sharp(iconBuf).resize(32, 32).png().toBuffer();
                const png16 = await sharp(iconBuf).resize(16, 16).png().toBuffer();

                // ICO format: header(6) + 1 entry(16) + PNG data
                const icoHeader = Buffer.alloc(6);
                icoHeader.writeUInt16LE(0, 0);
                icoHeader.writeUInt16LE(1, 2);
                icoHeader.writeUInt16LE(1, 4);

                const icoEntry = Buffer.alloc(16);
                icoEntry[0] = 0;
                icoEntry[1] = 0;
                icoEntry.writeUInt16LE(1, 2);
                icoEntry.writeUInt16LE(32, 4);
                icoEntry.writeUInt32LE(png256.length, 8);
                icoEntry.writeUInt32LE(22, 12);

                const ico = Buffer.concat([icoHeader, icoEntry, png256]);
                fs.writeFileSync(path.join(buildDir, 'logo.ico'), ico);
                console.log('[OK] Generated logo.ico');

                // ICNS: simple icon resource with PNG payloads
                const icnsIcon = Buffer.alloc(4);
                icnsIcon.write('icns', 0);
                const icnsRsrc24 = Buffer.alloc(8);
                icnsRsrc24.write('ic24', 0);
                icnsRsrc24.writeUInt32BE(png256.length + 8, 4);
                const icnsRsrc12 = Buffer.alloc(8);
                icnsRsrc12.write('ic12', 0);
                icnsRsrc12.writeUInt32BE(png128.length + 8, 4);
                const icnsRsrc08 = Buffer.alloc(8);
                icnsRsrc08.write('ic08', 0);
                icnsRsrc08.writeUInt32BE(png256.length + 8, 4);
                const totalSize = 4 + 4 + (8 + png256.length) + (8 + png128.length) + (8 + png256.length);
                const icnsSizeBuf = Buffer.alloc(4);
                icnsSizeBuf.writeUInt32BE(totalSize, 0);
                const icns = Buffer.concat([icnsIcon, icnsSizeBuf, icnsRsrc24, png256, icnsRsrc12, png128, icnsRsrc08, png256]);
                fs.writeFileSync(path.join(buildDir, 'logo.icns'), icns);
                console.log('[OK] Generated logo.icns');

                // tray icon: 16x16 PNG
                fs.writeFileSync(path.join(buildDir, 'tray.png'), png16);
                fs.writeFileSync(path.join(buildDir, 'tray.ico'), Buffer.concat([
                    (() => { const h = Buffer.alloc(6); h.writeUInt16LE(0,0); h.writeUInt16LE(1,2); h.writeUInt16LE(1,4); return h; })(),
                    (() => { const e = Buffer.alloc(16); e.writeUInt16LE(1,2); e.writeUInt16LE(32,4); e.writeUInt32BE(png16.length,8); e.writeUInt32BE(22,12); return e; })(),
                    png16
                ]));
                console.log('[OK] Generated tray.png and tray.ico');

            } catch(err) {
                console.warn('[WARN] sharp not available, copying icon.png as-is. Install sharp for auto ICO/ICNS conversion:', err.message);
                fs.copyFileSync(sourceIcon, path.join(buildDir, 'logo.png'));
            }
        })();
    }
    console.log('');
} else {
    console.log('[INFO] No iconPath configured or file not found, skipping icon generation\n');
}

// ========== 3.6 复制登录页背景图 ==========
const sourceLoginBg = oemConfig.loginBgPath ? path.join(__dirname, oemConfig.loginBgPath) : null;
if (sourceLoginBg && fs.existsSync(sourceLoginBg)) {
    const loginBgTarget = path.join(__dirname, 'public', 'login-bg.png');
    fs.copyFileSync(sourceLoginBg, loginBgTarget);
    console.log('[OK] Copied login-bg.png to public/');

    const allPublicDirs2 = fs.readdirSync(__dirname).filter(d => {
        const sub = path.join(__dirname, d, 'public');
        return fs.existsSync(sub) && d !== 'node_modules';
    });
    allPublicDirs2.forEach(d => {
        const target = path.join(__dirname, d, 'public', 'login-bg.png');
        try { fs.copyFileSync(sourceLoginBg, target); console.log('[OK] Copied login-bg to ' + d + '/public/'); } catch(e) {}
    });
    console.log('');
} else {
    console.log('[INFO] No loginBgPath configured or file not found, skipping login background\n');
}

// ========== 4. 更新 electron-builder.json5 ==========
const builderConfigPath = path.join(__dirname, 'electron-builder.json5');
if (fs.existsSync(builderConfigPath)) {
    console.log('Processing: ' + builderConfigPath);
    const ok = replaceInFile(builderConfigPath, [
        [/"appId":\s*"[^"]*"/, '"appId": ' + quoted(oemConfig.brandShortName)],
        [/"productName":\s*"[^"]*"/, '"productName": ' + quoted(oemConfig.brandName)],
        [/"identityName":\s*"[^"]*"/, '"identityName": ' + quoted(oemConfig.brandShortName)],
        [/"publisherDisplayName":\s*"[^"]*"/, '"publisherDisplayName": ' + quoted(oemConfig.brandDisplayName)],
        [/"maintainer":\s*"[^"]*"/, '"maintainer": ' + quoted(oemConfig.brandDisplayName)],
    ]);
    if (ok) console.log('[OK] electron-builder.json5 updated\n');
}

console.log('========================================');
console.log('OEM Apply Done!');
console.log('NEXT STEP: run npm run build to rebuild');
console.log('========================================\n');
