import fs from 'node:fs';
import path from 'node:path';
import { execFileSync } from 'node:child_process';
import { getConfigDir, getActiveHost, extractHostname } from './config.js';
import { t } from './i18n/translate.js';
const TOKEN_TTL_MS = 20 * 60 * 60 * 1000; // 20 hours
const POLL_INTERVAL_MS = 2000;
const POLL_TIMEOUT_MS = 60000;
function tokensFile() {
    return path.join(getConfigDir(), 'tokens.json');
}
function ensureDir() {
    const dir = getConfigDir();
    fs.mkdirSync(dir, { recursive: true });
}
function loadAllTokens() {
    try {
        if (fs.existsSync(tokensFile())) {
            return JSON.parse(fs.readFileSync(tokensFile(), 'utf8'));
        }
    }
    catch { }
    return {};
}
function saveAllTokens(tokens) {
    ensureDir();
    fs.writeFileSync(tokensFile(), JSON.stringify(tokens, null, 2));
}
export function loadToken(hostUrl) {
    const tokens = loadAllTokens();
    const entry = tokens[hostUrl];
    if (!entry || !entry.token)
        return null;
    if (entry.updatedAt) {
        const age = Date.now() - new Date(entry.updatedAt).getTime();
        if (age > TOKEN_TTL_MS) {
            clearToken(hostUrl);
            return null;
        }
    }
    return { host: hostUrl, token: entry.token, updatedAt: entry.updatedAt };
}
export function saveToken(token, hostUrl, umi_locale) {
    const tokens = loadAllTokens();
    tokens[hostUrl] = { token, umi_locale, updatedAt: new Date().toISOString() };
    saveAllTokens(tokens);
}
export function clearToken(hostUrl) {
    const tokens = loadAllTokens();
    delete tokens[hostUrl];
    saveAllTokens(tokens);
}
export function resolveHost(override) {
    if (override)
        return override;
    return getActiveHost();
}
function extractViaOsascript(hostUrl) {
    if (process.platform !== 'darwin')
        return { token: null, error: 'not_mac' };
    const hostname = extractHostname(hostUrl);
    // 尝试 Chrome
    const chromeResult = extractFromChrome(hostname);
    if (chromeResult.token)
        return { ...chromeResult, browser: 'Chrome' };
    if (chromeResult.error === 'no_js_permission')
        return { ...chromeResult, browser: 'Chrome' };
    // 尝试 Safari（Chrome 未找到 tab 时）
    const safariResult = extractFromSafari(hostname);
    if (safariResult.token)
        return { ...safariResult, browser: 'Safari' };
    if (safariResult.error === 'no_js_permission')
        return { ...safariResult, browser: 'Safari' };
    // 都没找到
    return { token: null, error: 'no_tab' };
}
function extractFromChrome(hostname) {
    const lines = [
        'tell application "Google Chrome"',
        '  repeat with w in windows',
        '    repeat with t in tabs of w',
        `      if URL of t contains "${hostname}" then`,
        `        set js to "JSON.stringify({token: localStorage.getItem('ACCESS_TOKEN'), umi_locale: localStorage.getItem('umi_locale')})"`,
        '        return execute t javascript js',
        '      end if',
        '    end repeat',
        '  end repeat',
        '  return "NO_TAB_FOUND"',
        'end tell',
    ];
    try {
        const args = lines.flatMap(line => ['-e', line]);
        const result = execFileSync('osascript', args, { encoding: 'utf8', timeout: 5000 }).trim();
        if (result === 'NO_TAB_FOUND')
            return { token: null, error: 'no_tab' };
        if (!result || result === 'missing value')
            return { token: null, error: 'no_token' };
        const parsed = JSON.parse(result);
        const tok = typeof parsed.token === 'string' ? parsed.token.replace(/^["']|["']$/g, '') : null;
        return { token: tok, umi_locale: parsed.umi_locale ?? undefined, error: tok ? null : 'no_token' };
    }
    catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        if (msg.includes('not allowed') || msg.includes('assistive access') || msg.includes('(-1743)')) {
            return { token: null, error: 'no_js_permission' };
        }
        return { token: null, error: 'no_tab' };
    }
}
function extractFromSafari(hostname) {
    const lines = [
        'tell application "Safari"',
        '  repeat with w in windows',
        '    repeat with t in tabs of w',
        `      if URL of t contains "${hostname}" then`,
        `        set js to "JSON.stringify({token: localStorage.getItem('ACCESS_TOKEN'), umi_locale: localStorage.getItem('umi_locale')})"`,
        '        return do JavaScript js in t',
        '      end if',
        '    end repeat',
        '  end repeat',
        '  return "NO_TAB_FOUND"',
        'end tell',
    ];
    try {
        const args = lines.flatMap(line => ['-e', line]);
        const result = execFileSync('osascript', args, { encoding: 'utf8', timeout: 5000 }).trim();
        if (result === 'NO_TAB_FOUND')
            return { token: null, error: 'no_tab' };
        if (!result || result === 'missing value')
            return { token: null, error: 'no_token' };
        const parsed = JSON.parse(result);
        const tok = typeof parsed.token === 'string' ? parsed.token.replace(/^["']|["']$/g, '') : null;
        return { token: tok, umi_locale: parsed.umi_locale ?? undefined, error: tok ? null : 'no_token' };
    }
    catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        if (msg.includes('not allowed') || msg.includes('assistive access')) {
            return { token: null, error: 'no_js_permission' };
        }
        return { token: null, error: 'no_tab' };
    }
}
async function openAndPoll(hostUrl) {
    process.stderr.write(t('auth.no_tab_found', { host: hostUrl }) + '\n');
    process.stderr.write(t('auth.please_login') + '\n');
    process.stderr.write(t('auth.other_browser_hint') + '\n');
    // 尝试打开 Chrome
    try {
        const chromeScript = [
            'tell application "Google Chrome"',
            '  activate',
            '  if (count of windows) > 0 then',
            `    make new tab at end of tabs of window 1 with properties {URL:"${hostUrl}"}`,
            '  else',
            `    open location "${hostUrl}"`,
            '  end if',
            'end tell',
        ];
        execFileSync('osascript', chromeScript.flatMap(line => ['-e', line]), { timeout: 5000 });
    }
    catch {
        // Chrome 不存在，尝试 Safari
        try {
            const safariScript = [
                'tell application "Safari"',
                '  activate',
                `  open location "${hostUrl}"`,
                'end tell',
            ];
            execFileSync('osascript', safariScript.flatMap(line => ['-e', line]), { timeout: 5000 });
        }
        catch {
            // 都不存在，用系统默认方式打开
            process.stderr.write(t('auth.could_not_open_browser', { host: hostUrl }) + '\n');
        }
    }
    const deadline = Date.now() + POLL_TIMEOUT_MS;
    while (Date.now() < deadline) {
        await new Promise(r => setTimeout(r, POLL_INTERVAL_MS));
        const { token, error, browser } = extractViaOsascript(hostUrl);
        if (token) {
            process.stderr.write(t('auth.token_captured_from_browser', { browser: browser ?? 'unknown', host: hostUrl }) + '\n');
            return { token, browser };
        }
        if (error === 'no_js_permission')
            return { token: null, browser };
    }
    process.stderr.write(t('auth.polling_timeout', { seconds: POLL_TIMEOUT_MS / 1000 }) + '\n');
    return { token: null };
}
/** 读取 AE 项目 language（umi_locale）—— 优先浏览器 localStorage，fallback 缓存 */
export function readUmilocal(hostUrl) {
    if (process.platform === 'darwin') {
        const hostname = extractHostname(hostUrl);
        // 尝试 Chrome
        try {
            const lines = [
                'tell application "Google Chrome"',
                '  repeat with w in windows',
                '    repeat with t in tabs of w',
                `      if URL of t contains "${hostname}" then`,
                `        return execute t javascript "localStorage.getItem('umi_locale')"`,
                '      end if',
                '    end repeat',
                '  end repeat',
                '  return ""',
                'end tell',
            ];
            const r = execFileSync('osascript', lines.flatMap(l => ['-e', l]), { encoding: 'utf8', timeout: 3000 }).trim();
            if (r && r !== 'missing value')
                return r;
        }
        catch { /* Chrome 不可用 */ }
        // 尝试 Safari
        try {
            const lines = [
                'tell application "Safari"',
                '  repeat with w in windows',
                '    repeat with t in tabs of w',
                `      if URL of t contains "${hostname}" then`,
                `        return do JavaScript "localStorage.getItem('umi_locale')" in t`,
                '      end if',
                '    end repeat',
                '  end repeat',
                '  return ""',
                'end tell',
            ];
            const r = execFileSync('osascript', lines.flatMap(l => ['-e', l]), { encoding: 'utf8', timeout: 3000 }).trim();
            if (r && r !== 'missing value')
                return r;
        }
        catch { /* Safari 也不可用 */ }
    }
    // fallback: 读缓存
    const tokens = loadAllTokens();
    return tokens[hostUrl]?.umi_locale;
}
/** 通过 osascript 写浏览器 localStorage 的 umi_locale（macOS only），返回是否成功 */
export function writeUmilocale(hostUrl, value) {
    if (process.platform !== 'darwin')
        return false;
    const hostname = extractHostname(hostUrl);
    // 尝试 Chrome
    const chromeLines = [
        'tell application "Google Chrome"',
        '  repeat with w in windows',
        '    repeat with t in tabs of w',
        `      if URL of t contains "${hostname}" then`,
        `        execute t javascript "localStorage.setItem('umi_locale', '${value}')"`,
        '        return "OK"',
        '      end if',
        '    end repeat',
        '  end repeat',
        '  return "NO_TAB_FOUND"',
        'end tell',
    ];
    try {
        const r = execFileSync('osascript', chromeLines.flatMap(l => ['-e', l]), { encoding: 'utf8', timeout: 5000 }).trim();
        if (r === 'OK')
            return true;
    }
    catch { /* Chrome 不可用，尝试 Safari */ }
    // 尝试 Safari
    const safariLines = [
        'tell application "Safari"',
        '  repeat with w in windows',
        '    repeat with t in tabs of w',
        `      if URL of t contains "${hostname}" then`,
        `        do JavaScript "localStorage.setItem('umi_locale', '${value}')" in t`,
        '        return "OK"',
        '      end if',
        '    end repeat',
        '  end repeat',
        '  return "NO_TAB_FOUND"',
        'end tell',
    ];
    try {
        const r = execFileSync('osascript', safariLines.flatMap(l => ['-e', l]), { encoding: 'utf8', timeout: 5000 }).trim();
        return r === 'OK';
    }
    catch { /* Safari 也不可用 */ }
    return false;
}
export async function getToken(hostUrl) {
    if (!hostUrl) {
        throw new Error(t('auth.no_ae_host'));
    }
    // 1. Environment variable
    if (process.env.AE_TOKEN) {
        return { token: process.env.AE_TOKEN, browser: 'env' };
    }
    // 2. Cached token
    const cached = loadToken(hostUrl);
    if (cached && cached.token)
        return { token: cached.token, browser: 'cache' };
    // 3. osascript extraction (Chrome + Safari)
    const { token: extracted, error, browser } = extractViaOsascript(hostUrl);
    if (error === 'no_js_permission') {
        throw new Error(t('auth.js_permission_error', { browser: browser ?? 'Browser' }));
    }
    if (error === 'not_mac') {
        throw new Error(t('auth.not_mac_error'));
    }
    if (extracted) {
        saveToken(extracted, hostUrl);
        return { token: extracted, browser };
    }
    // 4. Open browser and poll
    const polled = await openAndPoll(hostUrl);
    if (polled.token) {
        saveToken(polled.token, hostUrl);
        return { token: polled.token, browser: polled.browser };
    }
    throw new Error(t('auth.cannot_obtain_token', { host: hostUrl }));
}
