import fs from "node:fs";
import path from "node:path";
import { persistModuleStateRow } from "../state/module-state-sidecar-migration.js";
import { UnifiedStateDb } from "../state/unified-state-db.js";
import { planningSqliteDatabaseRelativePath } from "../../modules/task-engine/planning-config.js";
import { isPlanArtifactV1 } from "./plan-artifact-v1.js";
/**
 * Canonical PlanArtifact JSON files (gitignored workspace data):
 *   `.workspace-kit/planning/plan-artifacts/{planId}/artifact.v{version}.json`
 *
 * Fast dashboard / list pointer in planning SQLite module-state:
 *   module id `planning-plan-artifact:{planId}` → {@link PlanArtifactIndexStateV1}
 */
export const PLAN_ARTIFACT_ROOT_REL = path.join(".workspace-kit", "planning", "plan-artifacts");
export const PLAN_ARTIFACT_MODULE_ID_PREFIX = "planning-plan-artifact:";
const INDEX_STATE_SCHEMA = 1;
function dbRelativePath(workspacePath, effectiveConfig) {
    return planningSqliteDatabaseRelativePath({
        workspacePath,
        effectiveConfig
    });
}
export function planArtifactModuleId(planId) {
    return `${PLAN_ARTIFACT_MODULE_ID_PREFIX}${planId}`;
}
export function getPlanArtifactStoragePaths(workspacePath, planId) {
    const planDirRelative = path.join(PLAN_ARTIFACT_ROOT_REL, planId);
    const rootAbsolute = path.resolve(workspacePath, PLAN_ARTIFACT_ROOT_REL);
    const planDirAbsolute = path.resolve(workspacePath, planDirRelative);
    return {
        rootRelative: PLAN_ARTIFACT_ROOT_REL,
        rootAbsolute,
        planDirRelative,
        planDirAbsolute,
        artifactFileRelative: (version) => path.join(planDirRelative, `artifact.v${version}.json`),
        artifactFileAbsolute: (version) => path.join(planDirAbsolute, `artifact.v${version}.json`),
        moduleId: planArtifactModuleId(planId)
    };
}
export function upsertPlanArtifactIndexOnDatabase(db, moduleId, index) {
    const updatedAt = new Date().toISOString();
    db.prepare(`INSERT INTO workspace_module_state (module_id, state_schema_version, state_json, updated_at)
     VALUES (?, ?, ?, ?)
     ON CONFLICT(module_id) DO UPDATE SET
       state_schema_version=excluded.state_schema_version,
       state_json=excluded.state_json,
       updated_at=excluded.updated_at`).run(moduleId, INDEX_STATE_SCHEMA, JSON.stringify(index), updatedAt);
}
function indexFromArtifact(artifact) {
    return {
        schemaVersion: 1,
        planId: artifact.planId,
        currentVersion: artifact.version,
        planRef: artifact.planRef,
        status: artifact.status,
        title: artifact.identity.title,
        planningType: artifact.identity.planningType,
        updatedAt: artifact.provenance.updatedAt,
        wbsRowCount: artifact.wbs.length,
        openQuestionCount: artifact.openQuestions.length
    };
}
function parseIndex(raw) {
    if (!raw || typeof raw !== "object" || Array.isArray(raw))
        return null;
    const row = raw;
    if (row.schemaVersion !== 1 || typeof row.planId !== "string")
        return null;
    return row;
}
function listVersionFiles(planDirAbsolute) {
    if (!fs.existsSync(planDirAbsolute))
        return [];
    const names = fs.readdirSync(planDirAbsolute);
    const versions = [];
    for (const name of names) {
        const match = /^artifact\.v(\d+)\.json$/.exec(name);
        if (match) {
            versions.push(Number(match[1]));
        }
    }
    return versions.sort((a, b) => a - b);
}
export function resolveLatestPlanArtifactVersion(workspacePath, planId) {
    const paths = getPlanArtifactStoragePaths(workspacePath, planId);
    const fromDisk = listVersionFiles(paths.planDirAbsolute);
    if (fromDisk.length > 0) {
        return fromDisk[fromDisk.length - 1] ?? null;
    }
    const rel = dbRelativePath(workspacePath);
    const db = new UnifiedStateDb(workspacePath, rel);
    const index = parseIndex(db.getModuleState(paths.moduleId)?.state);
    return index?.currentVersion ?? null;
}
export function writePlanArtifactVersion(workspacePath, artifact, options) {
    const effectiveConfig = options?.effectiveConfig;
    if (!isPlanArtifactV1(artifact)) {
        throw new Error("writePlanArtifactVersion requires a PlanArtifact v1 document");
    }
    const paths = getPlanArtifactStoragePaths(workspacePath, artifact.planId);
    fs.mkdirSync(paths.planDirAbsolute, { recursive: true });
    const target = paths.artifactFileAbsolute(artifact.version);
    const temp = `${target}.tmp`;
    const payload = `${JSON.stringify(artifact, null, 2)}\n`;
    fs.writeFileSync(temp, payload, "utf8");
    fs.renameSync(temp, target);
    const index = indexFromArtifact(artifact);
    if (options?.sqliteDb) {
        upsertPlanArtifactIndexOnDatabase(options.sqliteDb, paths.moduleId, index);
    }
    else {
        persistModuleStateRow({
            workspacePath,
            databaseRelativePath: dbRelativePath(workspacePath, effectiveConfig),
            moduleId: paths.moduleId,
            stateSchemaVersion: INDEX_STATE_SCHEMA,
            state: index
        });
    }
    return paths;
}
export function readPlanArtifactVersion(workspacePath, planId, version) {
    const paths = getPlanArtifactStoragePaths(workspacePath, planId);
    const file = paths.artifactFileAbsolute(version);
    if (!fs.existsSync(file))
        return null;
    try {
        const raw = JSON.parse(fs.readFileSync(file, "utf8"));
        return isPlanArtifactV1(raw) ? raw : null;
    }
    catch {
        return null;
    }
}
export function readLatestPlanArtifact(workspacePath, planId) {
    const version = resolveLatestPlanArtifactVersion(workspacePath, planId);
    if (version === null)
        return null;
    return readPlanArtifactVersion(workspacePath, planId, version);
}
export function readPlanArtifactIndex(workspacePath, planId, effectiveConfig) {
    const paths = getPlanArtifactStoragePaths(workspacePath, planId);
    const db = new UnifiedStateDb(workspacePath, dbRelativePath(workspacePath, effectiveConfig));
    return parseIndex(db.getModuleState(paths.moduleId)?.state);
}
/**
 * Persist a new version (increments from latest on disk). Caller supplies merged document body.
 */
export function writeNextPlanArtifactVersion(workspacePath, artifact, options) {
    const latest = resolveLatestPlanArtifactVersion(workspacePath, artifact.planId);
    const version = latest === null ? 1 : latest + 1;
    const { version: _prior, ...body } = artifact;
    const full = {
        ...body,
        version
    };
    const paths = writePlanArtifactVersion(workspacePath, full, options);
    return { artifact: full, paths };
}
export function listPlanArtifactSummaries(workspacePath, effectiveConfig) {
    const db = new UnifiedStateDb(workspacePath, dbRelativePath(workspacePath, effectiveConfig));
    return db
        .listModuleStates()
        .filter((row) => row.moduleId.startsWith(PLAN_ARTIFACT_MODULE_ID_PREFIX))
        .map((row) => parseIndex(row.state))
        .filter((row) => row !== null)
        .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
}
