import DryRunGraphModelMigrationPlanRequest from "../../../../src/domain/migrations/DryRunGraphModelMigrationPlanRequest.js";
import GenesisEquivalenceComparisonBasis from "../../../../src/domain/migrations/GenesisEquivalenceComparisonBasis.js";
import GraphModelMigrationBasis from "../../../../src/domain/migrations/GraphModelMigrationBasis.js";
import GraphModelMigrationEdgeMapping from "../../../../src/domain/migrations/GraphModelMigrationEdgeMapping.js";
import GraphModelMigrationNodeMapping from "../../../../src/domain/migrations/GraphModelMigrationNodeMapping.js";
import GraphModelMigrationNotice from "../../../../src/domain/migrations/GraphModelMigrationNotice.js";
import GraphModelMigrationRuntimeReplayRequest from "../../../../src/domain/migrations/GraphModelMigrationRuntimeReplayRequest.js";
import V17GoldenGraphFixtureManifest, { V17GoldenContentFact, V17GoldenEdgeFact, V17GoldenNodeFact, } from "./V17GoldenGraphFixtureManifest.js";
import { runGraphModelMigrationCommand, } from "./GraphModelMigrationCommand.js";
import { verifyGraphModelMigrationProductionRuntimeReplay } from "./GraphModelMigrationProductionRuntimeReplayProvider.js";
import { buildV17GoldenFixturePropertyMappings } from "./V17GoldenGraphFixturePropertyMappings.js";
import { createV17GoldenFixtureScratchReadingProvider } from "./V17GoldenFixtureScratchReadingProvider.js";
import { collectGraphModelMigrationSourceInventory } from "./GraphModelMigrationSourceInventoryCollector.js";
import { buildV17RestoredPublicReadLegacyReading } from "./V17RestoredPublicReadLegacyReadingBuilder.js";
import { restoreV17GoldenGraphFixture, } from "./V17GoldenGraphFixtureRestore.js";
import { runMigrationGit } from "./GitMigrationCommandRunner.js";
export { buildV17GoldenFixturePropertyMappings } from "./V17GoldenGraphFixturePropertyMappings.js";
export { createV17GoldenFixtureScratchReadingProvider } from "./V17GoldenFixtureScratchReadingProvider.js";
const DEFAULT_SCRATCH_REF_PREFIX = 'refs/warp-migration-scratch';
export const V17_WET_RUN_DRIFT_CHECK_PASSED = 'passed';
export const V17_WET_RUN_DRIFT_CHECK_FAILED = 'failed';
/** Evidence produced by the v17 fixture wet-run harness. */
export class V17GoldenGraphFixtureWetRunHarnessResult {
    restoreResult;
    commandResult;
    runtimeReplayResult;
    driftCheckResult;
    constructor(restoreResult, commandResult, runtimeReplayResult, driftCheckResult) {
        this.restoreResult = restoreResult;
        this.commandResult = commandResult;
        this.runtimeReplayResult = runtimeReplayResult;
        this.driftCheckResult = driftCheckResult;
        Object.freeze(this);
    }
}
/** Source-ref drift evidence captured before any future finalization step. */
export class V17GoldenGraphFixtureWetRunDriftCheckResult {
    status;
    checkedRefCount;
    fatalErrors;
    constructor(status, checkedRefCount, fatalErrors) {
        this.status = status;
        this.checkedRefCount = checkedRefCount;
        this.fatalErrors = fatalErrors;
        Object.freeze(this);
    }
}
export class V17GoldenGraphFixtureWetRunHarnessError extends Error {
    constructor(message) {
        super(message);
        this.name = 'V17GoldenGraphFixtureWetRunHarnessError';
    }
}
/** Restores the v17 fixture and runs the v18 migration path against scratch history. */
export async function runV17GoldenGraphFixtureWetRun(options) {
    const restoreResult = await restoreV17GoldenGraphFixture({
        manifestPath: requireNonEmptyString(options.manifestPath, 'manifestPath'),
        targetDirectory: requireNonEmptyString(options.targetDirectory, 'targetDirectory'),
    });
    const scratchRefName = requireNonEmptyString(options.scratchRefName ?? defaultScratchRefName(restoreResult.manifest), 'scratchRefName');
    const inventory = await collectGraphModelMigrationSourceInventory({
        repositoryPath: restoreResult.repositoryPath,
        graphId: restoreResult.manifest.graphId,
        fixtureManifest: restoreResult.manifest,
    });
    const dryRunRequest = dryRunRequestForManifest(restoreResult.manifest, inventory);
    const commandResult = await runGraphModelMigrationCommand({
        repositoryPath: restoreResult.repositoryPath,
        dryRunRequest,
        scratchRefName,
        equivalenceBasis: equivalenceBasisForRequest(dryRunRequest),
        legacyReading: null,
        scratchReading: null,
        readingProviders: {
            legacyReading: async () => await buildV17RestoredPublicReadLegacyReading({
                repositoryPath: restoreResult.repositoryPath,
                manifest: restoreResult.manifest,
            }),
            scratchReading: createV17GoldenFixtureScratchReadingProvider({
                sourceRepositoryPath: restoreResult.repositoryPath,
                manifest: restoreResult.manifest,
                runtimeRepositoryPath: options.runtimeRepositoryPath ?? null,
            }),
        },
        finalization: null,
    });
    const scratchWriteResult = commandResult.scratchWriteResult;
    const runtimeReplayResult = scratchWriteResult !== null
        && scratchWriteResult.scratchRef !== null
        && scratchWriteResult.scratchHead !== null
        ? await verifyGraphModelMigrationProductionRuntimeReplay({
            sourceRepositoryPath: restoreResult.repositoryPath,
            runtimeRepositoryPath: options.runtimeRepositoryPath ?? null,
            request: new GraphModelMigrationRuntimeReplayRequest({
                graphId: restoreResult.manifest.graphId,
                writerId: 'scratch-migration',
                scratchRef: scratchWriteResult.scratchRef,
                scratchHead: scratchWriteResult.scratchHead,
            }),
        })
        : null;
    const driftCheckResult = await checkV17GoldenGraphFixtureWetRunDrift({
        repositoryPath: restoreResult.repositoryPath,
        manifest: restoreResult.manifest,
    });
    return new V17GoldenGraphFixtureWetRunHarnessResult(restoreResult, commandResult, runtimeReplayResult, driftCheckResult);
}
/** Verifies restored source writer refs still match manifest evidence. */
export async function checkV17GoldenGraphFixtureWetRunDrift(options) {
    const repositoryPath = requireNonEmptyString(options.repositoryPath, 'repositoryPath');
    const manifest = requireManifest(options.manifest);
    const fatalErrors = [];
    for (const chain of manifest.writerChains) {
        const observedHead = await gitTextOrNull(repositoryPath, [
            'show-ref',
            '--verify',
            '--hash',
            chain.refName,
        ]);
        if (observedHead !== chain.expectedHead) {
            fatalErrors.push(GraphModelMigrationNotice.fatal('E_WET_RUN_SOURCE_REF_DRIFT', `source ref ${chain.refName} expected ${chain.expectedHead}, got ${observedHead ?? '(missing)'}`));
            continue;
        }
        const observedPatchCount = Number(await gitTextOrNull(repositoryPath, [
            'rev-list',
            '--count',
            chain.refName,
        ]));
        if (observedPatchCount !== chain.patchCount) {
            fatalErrors.push(GraphModelMigrationNotice.fatal('E_WET_RUN_SOURCE_REF_PATCH_COUNT_DRIFT', `source ref ${chain.refName} expected ${chain.patchCount} patches, got ${observedPatchCount}`));
        }
    }
    return new V17GoldenGraphFixtureWetRunDriftCheckResult(fatalErrors.length === 0 ? V17_WET_RUN_DRIFT_CHECK_PASSED : V17_WET_RUN_DRIFT_CHECK_FAILED, manifest.writerChains.length, fatalErrors);
}
function dryRunRequestForManifest(manifest, inventory) {
    return new DryRunGraphModelMigrationPlanRequest({
        inventory,
        requiredContentKeys: manifest.visibleFacts
            .filter((fact) => fact instanceof V17GoldenContentFact)
            .map((fact) => fact.key),
        nodeMappings: manifest.visibleFacts
            .filter((fact) => fact instanceof V17GoldenNodeFact)
            .map((fact) => new GraphModelMigrationNodeMapping({
            legacyNodeId: fact.key,
            targetNodeId: fact.key,
        })),
        edgeMappings: manifest.visibleFacts
            .filter((fact) => fact instanceof V17GoldenEdgeFact)
            .map((fact) => new GraphModelMigrationEdgeMapping({
            legacyEdgeId: fact.key,
            targetEdgeId: fact.key,
        })),
        propertyMappings: buildV17GoldenFixturePropertyMappings(manifest),
    });
}
function equivalenceBasisForRequest(request) {
    const sourceBasis = request.inventory.sourceBasis;
    if (sourceBasis === null) {
        throw new V17GoldenGraphFixtureWetRunHarnessError('wet-run request must have a source basis');
    }
    return new GenesisEquivalenceComparisonBasis({
        legacyBasis: sourceBasis,
        migratedBasis: new GraphModelMigrationBasis({
            graphId: sourceBasis.graphId,
            basisId: `${sourceBasis.basisId}:v18-dry-run`,
        }),
    });
}
function defaultScratchRefName(manifest) {
    return `${DEFAULT_SCRATCH_REF_PREFIX}/${manifest.graphId}/wet-run`;
}
function requireManifest(manifest) {
    if (!(manifest instanceof V17GoldenGraphFixtureManifest)) {
        throw new V17GoldenGraphFixtureWetRunHarnessError('manifest must be a V17GoldenGraphFixtureManifest');
    }
    return manifest;
}
function requireNonEmptyString(value, name) {
    if (typeof value !== 'string' || value.length === 0) {
        throw new V17GoldenGraphFixtureWetRunHarnessError(`${name} must be a non-empty string`);
    }
    return value;
}
async function gitTextOrNull(repositoryPath, args) {
    const result = await runMigrationGit(repositoryPath, args, null);
    if (!result.ok()) {
        return null;
    }
    return result.stdout.trim();
}
