import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
import { resolveFridayNextConfig } from "../config.js";
import { getHostOpenClawConfigSnapshot } from "../host-config.js";
import { getFridayNextRuntime } from "../runtime.js";
function currentHistoryDir() {
    const cfg = resolveFridayNextConfig(getHostOpenClawConfigSnapshot(getFridayNextRuntime().config));
    return cfg.historyDir;
}
function indexPath(historyDir = currentHistoryDir()) {
    return path.join(historyDir, "accounts", "index.json");
}
function normalizeDeviceId(deviceId) {
    return deviceId.trim().toUpperCase();
}
function readIndex(historyDir = currentHistoryDir()) {
    try {
        const parsed = JSON.parse(fs.readFileSync(indexPath(historyDir), "utf8"));
        return {
            accounts: parsed.accounts && typeof parsed.accounts === "object" ? parsed.accounts : {},
            deviceToAccount: parsed.deviceToAccount && typeof parsed.deviceToAccount === "object" ? parsed.deviceToAccount : {},
        };
    }
    catch {
        return { accounts: {}, deviceToAccount: {} };
    }
}
function writeIndex(index, historyDir = currentHistoryDir()) {
    const file = indexPath(historyDir);
    fs.mkdirSync(path.dirname(file), { recursive: true });
    fs.writeFileSync(file, JSON.stringify(index, null, 2), "utf8");
}
function touchAccount(index, accountId, deviceId) {
    const now = Date.now();
    const existing = index.accounts[accountId];
    const entry = existing ?? {
        accountId,
        createdAt: now,
        lastSeenAt: now,
        deviceIds: [],
    };
    entry.lastSeenAt = now;
    if (deviceId) {
        const normalized = normalizeDeviceId(deviceId);
        if (normalized && !entry.deviceIds.includes(normalized)) {
            entry.deviceIds.push(normalized);
        }
        if (normalized)
            index.deviceToAccount[normalized] = accountId;
    }
    index.accounts[accountId] = entry;
    return entry;
}
export function getOrCreateAccountId(params) {
    const historyDir = params.historyDir ?? currentHistoryDir();
    const index = readIndex(historyDir);
    const deviceId = normalizeDeviceId(params.deviceId);
    const claimed = params.claimAccountId?.trim();
    if (claimed) {
        const existed = Boolean(index.accounts[claimed]);
        if (existed || params.claimConfirmed === true) {
            touchAccount(index, claimed, deviceId);
            writeIndex(index, historyDir);
            return { accountId: claimed, status: existed ? "existing" : "new" };
        }
        const suggested = crypto.randomUUID();
        return { accountId: suggested, status: "unknown", suggestedAccountId: suggested };
    }
    const mapped = deviceId ? index.deviceToAccount[deviceId] : undefined;
    if (mapped && index.accounts[mapped]) {
        touchAccount(index, mapped, deviceId);
        writeIndex(index, historyDir);
        return { accountId: mapped, status: "existing" };
    }
    const existingAccounts = Object.values(index.accounts);
    if (existingAccounts.length === 1) {
        const accountId = existingAccounts[0].accountId;
        touchAccount(index, accountId, deviceId);
        writeIndex(index, historyDir);
        return { accountId, status: "existing" };
    }
    const accountId = crypto.randomUUID();
    touchAccount(index, accountId, deviceId);
    writeIndex(index, historyDir);
    return { accountId, status: "new" };
}
export function isKnownAccountId(accountId, historyDir = currentHistoryDir()) {
    const id = accountId.trim();
    if (!id)
        return false;
    return Boolean(readIndex(historyDir).accounts[id]);
}
export function resolveAccountIdFromRequest(req) {
    const raw = req.headers["x-account-id"];
    const accountId = Array.isArray(raw) ? raw[0] : raw;
    if (typeof accountId !== "string" || !accountId.trim())
        return null;
    const trimmed = accountId.trim();
    return isKnownAccountId(trimmed) ? trimmed : null;
}
