import { readKitSqliteUserVersion } from "../../core/state/workspace-kit-sqlite.js";
import path from "node:path";
export const SUBAGENT_KIT_MIN_USER_VERSION = 6;
const SUBAGENT_ID_RE = /^[a-z][a-z0-9._-]{0,63}$/i;
export function assertSubagentKitSchema(dbPathAbs) {
    const uv = readKitSqliteUserVersion(dbPathAbs);
    if (uv < SUBAGENT_KIT_MIN_USER_VERSION) {
        return {
            ok: false,
            message: `subagent commands require kit SQLite user_version >= ${SUBAGENT_KIT_MIN_USER_VERSION} (current ${uv}); open the workspace DB once with a current workspace-kit to migrate`
        };
    }
    return { ok: true };
}
export function validateSubagentId(raw) {
    const t = raw.trim();
    if (!t || !SUBAGENT_ID_RE.test(t)) {
        return null;
    }
    return t;
}
export function normalizeAllowedCommands(raw) {
    if (!Array.isArray(raw) || raw.length === 0) {
        return { ok: false, message: "allowedCommands must be a non-empty string array" };
    }
    const out = [];
    for (const x of raw) {
        if (typeof x !== "string") {
            return { ok: false, message: "allowedCommands entries must be strings" };
        }
        const c = x.trim();
        if (!c) {
            return { ok: false, message: "allowedCommands entries must be non-empty" };
        }
        if (c === "*" || c.includes("*")) {
            return { ok: false, message: "wildcard allowedCommands are rejected; list explicit workspace-kit command names" };
        }
        out.push(c);
    }
    if (out.length > 64) {
        return { ok: false, message: "allowedCommands max length is 64" };
    }
    return { ok: true, commands: out };
}
function parseJsonObject(raw) {
    if (!raw || !raw.trim())
        return null;
    try {
        const v = JSON.parse(raw);
        if (v && typeof v === "object" && !Array.isArray(v)) {
            return v;
        }
    }
    catch {
        return null;
    }
    return null;
}
export function rowToDefinition(r) {
    let allowed = [];
    try {
        const p = JSON.parse(String(r.allowed_commands_json ?? "[]"));
        if (Array.isArray(p)) {
            allowed = p.filter((x) => typeof x === "string");
        }
    }
    catch {
        allowed = [];
    }
    return {
        id: String(r.id),
        displayName: String(r.display_name ?? ""),
        description: String(r.description ?? ""),
        allowedCommands: allowed,
        retired: Number(r.retired) === 1,
        metadata: parseJsonObject(typeof r.metadata_json === "string" ? r.metadata_json : null),
        createdAt: String(r.created_at ?? ""),
        updatedAt: String(r.updated_at ?? "")
    };
}
export function insertDefinition(db, row) {
    db.prepare(`INSERT INTO kit_subagent_definitions (
      id, display_name, description, allowed_commands_json, retired, metadata_json, created_at, updated_at
    ) VALUES (?,?,?,?,0,?,?,?)`).run(row.id, row.displayName, row.description, JSON.stringify(row.allowedCommands), row.metadata ? JSON.stringify(row.metadata) : null, row.now, row.now);
}
export function updateDefinition(db, row) {
    db.prepare(`UPDATE kit_subagent_definitions SET
      display_name = ?, description = ?, allowed_commands_json = ?, metadata_json = ?, updated_at = ?
    WHERE id = ?`).run(row.displayName, row.description, JSON.stringify(row.allowedCommands), row.metadata ? JSON.stringify(row.metadata) : null, row.now, row.id);
}
export function getDefinitionById(db, id) {
    const r = db.prepare("SELECT * FROM kit_subagent_definitions WHERE id = ?").get(id);
    return r ? rowToDefinition(r) : null;
}
export function listDefinitions(db, includeRetired) {
    const sql = includeRetired
        ? "SELECT * FROM kit_subagent_definitions ORDER BY id"
        : "SELECT * FROM kit_subagent_definitions WHERE retired = 0 ORDER BY id";
    const rows = db.prepare(sql).all();
    return rows.map(rowToDefinition);
}
export function setDefinitionRetired(db, id, now) {
    const r = db.prepare("UPDATE kit_subagent_definitions SET retired = 1, updated_at = ? WHERE id = ?").run(now, id);
    return r.changes > 0;
}
export function insertSession(db, row) {
    db.prepare(`INSERT INTO kit_subagent_sessions (
      id, definition_id, execution_task_id, status, host_hint, metadata_json, created_at, updated_at
    ) VALUES (?,?,?,?,?,?,?,?)`).run(row.id, row.definitionId, row.executionTaskId, row.status, row.hostHint, row.metadata ? JSON.stringify(row.metadata) : null, row.now, row.now);
}
export function getSession(db, sessionId) {
    const r = db.prepare("SELECT * FROM kit_subagent_sessions WHERE id = ?").get(sessionId);
    if (!r)
        return null;
    return {
        id: String(r.id),
        definitionId: String(r.definition_id),
        executionTaskId: r.execution_task_id != null ? String(r.execution_task_id) : null,
        status: String(r.status),
        hostHint: r.host_hint != null ? String(r.host_hint) : null,
        metadata: parseJsonObject(typeof r.metadata_json === "string" ? r.metadata_json : null),
        createdAt: String(r.created_at ?? ""),
        updatedAt: String(r.updated_at ?? "")
    };
}
export function listSessions(db, filters) {
    const clauses = [];
    const params = [];
    if (filters.definitionId) {
        clauses.push("definition_id = ?");
        params.push(filters.definitionId);
    }
    if (filters.executionTaskId) {
        clauses.push("execution_task_id = ?");
        params.push(filters.executionTaskId);
    }
    const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
    const rows = db.prepare(`SELECT * FROM kit_subagent_sessions ${where} ORDER BY created_at DESC`).all(...params);
    return rows.map((r) => ({
        id: String(r.id),
        definitionId: String(r.definition_id),
        executionTaskId: r.execution_task_id != null ? String(r.execution_task_id) : null,
        status: String(r.status),
        hostHint: r.host_hint != null ? String(r.host_hint) : null,
        metadata: parseJsonObject(typeof r.metadata_json === "string" ? r.metadata_json : null),
        createdAt: String(r.created_at ?? ""),
        updatedAt: String(r.updated_at ?? "")
    }));
}
export function updateSessionStatus(db, sessionId, status, now) {
    const r = db.prepare("UPDATE kit_subagent_sessions SET status = ?, updated_at = ? WHERE id = ?").run(status, now, sessionId);
    return r.changes > 0;
}
export function insertMessage(db, row) {
    const info = db
        .prepare("INSERT INTO kit_subagent_messages (session_id, direction, body, created_at) VALUES (?,?,?,?)")
        .run(row.sessionId, row.direction, row.body, row.now);
    return Number(info.lastInsertRowid);
}
export function listMessagesForSession(db, sessionId) {
    const rows = db
        .prepare("SELECT id, session_id, direction, body, created_at FROM kit_subagent_messages WHERE session_id = ? ORDER BY id ASC")
        .all(sessionId);
    return rows.map((r) => ({
        id: Number(r.id),
        sessionId: String(r.session_id),
        direction: String(r.direction),
        body: String(r.body),
        createdAt: String(r.created_at ?? "")
    }));
}
export function summarizeSubagentsForDashboard(db) {
    const empty = {
        schemaVersion: 1,
        available: false,
        definitionsCount: 0,
        retiredDefinitionsCount: 0,
        openSessionsCount: 0,
        topOpenSessions: []
    };
    if (!db) {
        return empty;
    }
    const uvRaw = db.pragma("user_version", { simple: true });
    const uv = typeof uvRaw === "number" ? uvRaw : Number(uvRaw);
    if (!Number.isFinite(uv) || uv < SUBAGENT_KIT_MIN_USER_VERSION) {
        return empty;
    }
    try {
        const defRows = db.prepare("SELECT retired FROM kit_subagent_definitions").all();
        let retiredDefinitionsCount = 0;
        for (const r of defRows) {
            if (Number(r.retired) === 1) {
                retiredDefinitionsCount++;
            }
        }
        const definitionsCount = defRows.length;
        const sessRows = db
            .prepare(`SELECT id, definition_id, execution_task_id, status, updated_at FROM kit_subagent_sessions`)
            .all();
        const openSessions = sessRows.filter((r) => String(r.status ?? "") === "open");
        const topOpenSessions = [...openSessions]
            .sort((a, b) => String(b.updated_at ?? "").localeCompare(String(a.updated_at ?? "")))
            .slice(0, 15)
            .map((r) => ({
            sessionId: String(r.id),
            definitionId: String(r.definition_id),
            executionTaskId: r.execution_task_id != null ? String(r.execution_task_id) : null,
            status: String(r.status ?? ""),
            updatedAt: String(r.updated_at ?? "")
        }));
        return {
            schemaVersion: 1,
            available: true,
            definitionsCount,
            retiredDefinitionsCount,
            openSessionsCount: openSessions.length,
            topOpenSessions
        };
    }
    catch {
        return empty;
    }
}
export function resolveDbPathAbs(workspacePath, dbRel) {
    return path.resolve(workspacePath, dbRel);
}
