"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildArchitectureMigrationPreview = buildArchitectureMigrationPreview;
exports.previewArchitectureMigration = previewArchitectureMigration;
exports.renderArchitectureMigrationPreviewText = renderArchitectureMigrationPreviewText;
const path = __importStar(require("node:path"));
const architectureInit_1 = require("./architectureInit");
const architectureWorkspaceModel_1 = require("./architectureWorkspaceModel");
const architectureComponentDiscoveryDefaults_1 = require("./architectureComponentDiscoveryDefaults");
function normalizePreviewPath(value) {
    const normalized = value
        ?.replace(/\\/g, '/')
        .replace(/\/+/gu, '/')
        .replace(/^\.\//u, '')
        .replace(/\/+$/u, '')
        .trim();
    return normalized && normalized.length > 0 ? normalized : undefined;
}
function stableIdFromPath(value) {
    return value
        .toLowerCase()
        .replace(/[^a-z0-9]+/gu, '-')
        .replace(/^-+|-+$/gu, '') || 'component';
}
function titleFromPathSegment(value) {
    return value
        .split(/[-_ ]+/u)
        .filter((part) => part.length > 0)
        .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
        .join(' ') || value;
}
function isIgnoredPreviewPath(value) {
    const firstSegment = value.split('/')[0]?.toLowerCase();
    return firstSegment === 'test' ||
        firstSegment === 'tests' ||
        firstSegment === 'fixture' ||
        firstSegment === 'fixtures' ||
        firstSegment === 'smoke' ||
        firstSegment === 'docs' ||
        firstSegment === 'reports' ||
        firstSegment === '.archpilot' ||
        firstSegment === '.archpilot_';
}
function resolveComponentRoot(modulePath) {
    const normalizedPath = normalizePreviewPath(modulePath);
    if (!normalizedPath || isIgnoredPreviewPath(normalizedPath)) {
        return undefined;
    }
    const segments = normalizedPath.split('/');
    const [scope, name] = segments;
    if (!scope || !name) {
        return undefined;
    }
    if (scope === 'apps' ||
        scope === 'services' ||
        scope === 'packages' ||
        scope === 'libs' ||
        scope === 'libraries' ||
        scope === 'workers') {
        return `${scope}/${name}`;
    }
    return undefined;
}
function pickStackForKind(stacks, kind) {
    if (kind === 'frontend') {
        return stacks.frontendStack;
    }
    if (kind === 'library') {
        return stacks.libraryStack;
    }
    return stacks.backendStack;
}
function pickStacksForKind(stacks, kind) {
    const stack = pickStackForKind(stacks, kind);
    if (!stack) {
        return undefined;
    }
    if (kind === 'frontend') {
        return { frontendStack: stack };
    }
    if (kind === 'library') {
        return { libraryStack: stack };
    }
    return { backendStack: stack };
}
function inferKindForRoot(root, contract) {
    const [scope, name = ''] = root.split('/');
    const lowered = name.toLowerCase();
    if (scope === 'packages' || scope === 'libs' || scope === 'libraries') {
        return 'library';
    }
    if (scope === 'services') {
        return 'backend';
    }
    if (scope === 'workers') {
        return 'worker';
    }
    if (/(api|backend|server|service)/u.test(lowered)) {
        return 'backend';
    }
    if (/(web|frontend|client|admin|console|app)/u.test(lowered)) {
        return 'frontend';
    }
    if (contract.projectKinds.length === 1) {
        return contract.projectKinds[0];
    }
    return contract.projectKinds.includes('frontend') ? 'frontend' : 'backend';
}
function typeForKind(kind) {
    if (kind === 'frontend') {
        return 'frontend_app';
    }
    if (kind === 'backend') {
        return 'backend_service';
    }
    if (kind === 'worker') {
        return 'worker';
    }
    if (kind === 'library') {
        return 'library';
    }
    return 'component';
}
function projectKindsForKind(kind) {
    if (kind === 'frontend') {
        return ['frontend'];
    }
    if (kind === 'library') {
        return ['library'];
    }
    if (kind === 'backend' || kind === 'worker') {
        return ['backend'];
    }
    return undefined;
}
function inferComponentsFromLegacyModules(contract) {
    const groups = new Map();
    for (const [moduleId, moduleReference] of Object.entries(contract.modules)) {
        const componentRoot = resolveComponentRoot(moduleReference.path);
        if (!componentRoot) {
            continue;
        }
        const existing = groups.get(componentRoot);
        if (existing) {
            existing.modules[moduleId] = moduleReference;
            continue;
        }
        const kind = inferKindForRoot(componentRoot, contract);
        const stack = pickStackForKind(contract.stacks, kind);
        groups.set(componentRoot, {
            id: stableIdFromPath(componentRoot),
            name: titleFromPathSegment(componentRoot.split('/')[1] ?? componentRoot),
            path: componentRoot,
            kind,
            type: typeForKind(kind),
            ...(stack ? { stack } : {}),
            ...(projectKindsForKind(kind) ? { projectKinds: projectKindsForKind(kind) } : {}),
            ...(pickStacksForKind(contract.stacks, kind)
                ? { stacks: pickStacksForKind(contract.stacks, kind) }
                : {}),
            modules: { [moduleId]: moduleReference },
        });
    }
    return [...groups.values()]
        .sort((left, right) => left.id.localeCompare(right.id))
        .map((group) => ({
        id: group.id,
        name: group.name,
        path: group.path,
        type: group.type,
        kind: group.kind,
        ...(group.stack ? { stack: group.stack } : {}),
        ...(group.projectKinds ? { projectKinds: group.projectKinds } : {}),
        ...(group.stacks ? { stacks: group.stacks } : {}),
        modules: Object.fromEntries(Object.entries(group.modules).sort(([left], [right]) => left.localeCompare(right))),
    }));
}
function isConfiguredApi(apiStyle) {
    return apiStyle !== 'none';
}
function isConfiguredDatabase(database) {
    return database !== 'none';
}
function resourceIdFor(componentId, suffix) {
    return `${componentId}-${suffix}`
        .replace(/[^a-z0-9_-]+/giu, '-')
        .replace(/^-+|-+$/gu, '')
        .toLowerCase();
}
function inferResourcesForComponents(contract, components) {
    const owner = components.find((component) => component.kind === 'backend' || component.kind === 'worker') ?? components[0];
    if (!owner?.id) {
        return [];
    }
    const resources = [];
    if (isConfiguredApi(contract.apiStyle)) {
        resources.push({
            id: resourceIdFor(owner.id, 'api'),
            name: `${owner.name ?? owner.id} API`,
            type: 'api',
            provider: contract.apiStyle,
            ...(contract.artifacts.openApiSpec ? { path: contract.artifacts.openApiSpec } : {}),
            ownerComponent: owner.id,
            component: owner.id,
            components: [owner.id],
        });
    }
    if (isConfiguredDatabase(contract.database)) {
        resources.push({
            id: resourceIdFor(owner.id, 'database'),
            name: `${owner.name ?? owner.id} Database`,
            type: 'database',
            provider: contract.database,
            ...(contract.artifacts.sqlBaseline
                ? { path: contract.artifacts.sqlBaseline }
                : contract.structure.databaseRoot
                    ? { path: contract.structure.databaseRoot }
                    : {}),
            ownerComponent: owner.id,
            component: owner.id,
            components: [owner.id],
        });
    }
    return resources.sort((left, right) => (left.id ?? '').localeCompare(right.id ?? ''));
}
function hasDeclaredWorkspaceShape(contract) {
    return !!contract.components && Object.keys(contract.components).length > 0;
}
function hasDeclaredResources(contract) {
    return !!contract.resources && Object.keys(contract.resources).length > 0;
}
function mapDefaults(defaults) {
    return defaults.map((entry) => ({
        componentId: entry.componentId,
        adapterId: entry.adapterId,
        sourceRoots: [...entry.sourceRoots],
        moduleRoots: [...entry.moduleRoots],
        contractPattern: entry.contractDefaults.moduleContractPattern,
        importExtractionMode: entry.importExtractionMode,
        entrypointHints: [...entry.entrypointHints],
    }));
}
function mapModelComponents(model) {
    return model.components.map((component) => ({
        id: component.id,
        name: component.name,
        source: component.source,
        ...(component.path ? { path: component.path } : {}),
        ...(component.type ? { type: component.type } : {}),
        ...(component.kind ? { kind: component.kind } : {}),
        ...(component.stack ? { stack: component.stack } : {}),
        moduleIds: Object.keys(component.modules).sort((left, right) => left.localeCompare(right)),
    }));
}
function mapInferredComponents(components) {
    return components.map((component) => ({
        id: component.id ?? stableIdFromPath(component.path ?? component.name ?? 'component'),
        name: component.name ?? component.id ?? 'Component',
        source: 'inferred',
        ...(component.path ? { path: component.path } : {}),
        ...(component.type ? { type: component.type } : {}),
        ...(component.kind ? { kind: component.kind } : {}),
        ...(component.stack ? { stack: component.stack } : {}),
        moduleIds: Object.keys(component.modules ?? {}).sort((left, right) => left.localeCompare(right)),
    }));
}
function mapModelResources(model) {
    return (model.resources ?? []).map((resource) => ({
        id: resource.id,
        name: resource.name,
        source: 'declared',
        ...(resource.type ? { type: resource.type } : {}),
        ...(resource.provider ? { provider: resource.provider } : {}),
        ...(resource.path ? { path: resource.path } : {}),
        ...(resource.ownerComponent ? { ownerComponent: resource.ownerComponent } : {}),
        ...(resource.component ? { component: resource.component } : {}),
        components: [...resource.components],
    }));
}
function mapInferredResources(resources) {
    return resources.map((resource) => ({
        id: resource.id ?? stableIdFromPath(resource.name ?? 'resource'),
        name: resource.name ?? resource.id ?? 'Resource',
        source: 'inferred',
        ...(resource.type ? { type: resource.type } : {}),
        ...(resource.provider ? { provider: resource.provider } : {}),
        ...(resource.path ? { path: resource.path } : {}),
        ...(resource.ownerComponent ? { ownerComponent: resource.ownerComponent } : {}),
        ...(resource.component ? { component: resource.component } : {}),
        components: [...(resource.components ?? [])],
    }));
}
function buildArchitectureMigrationPreview(contract, configPath = '.archpilot/architecture.json') {
    const currentModel = (0, architectureWorkspaceModel_1.normalizeArchitectureWorkspaceModel)(contract);
    const declaredWorkspaceShape = hasDeclaredWorkspaceShape(contract);
    if (declaredWorkspaceShape) {
        const defaults = (0, architectureComponentDiscoveryDefaults_1.resolveArchitectureWorkspaceDiscoveryDefaultsFromModel)(currentModel);
        return {
            status: 'no_changes_needed',
            message: 'no changes needed',
            configPath,
            wouldWriteFiles: false,
            projectName: contract.projectName,
            repoTopology: contract.repoTopology,
            components: mapModelComponents(currentModel),
            resources: mapModelResources(currentModel),
            inferredDefaults: mapDefaults(defaults.components),
            notes: ['architecture.json already declares components/resources-compatible workspace fields.'],
        };
    }
    const inferredComponents = inferComponentsFromLegacyModules(contract);
    if (inferredComponents.length > 1) {
        const inferredResources = hasDeclaredResources(contract)
            ? []
            : inferResourcesForComponents(contract, inferredComponents);
        const proposedModel = (0, architectureWorkspaceModel_1.normalizeArchitectureWorkspaceModel)({
            ...contract,
            components: Object.fromEntries(inferredComponents.map((component) => [component.id ?? '', component])),
            ...(inferredResources.length > 0
                ? {
                    resources: Object.fromEntries(inferredResources.map((resource) => [resource.id ?? '', resource])),
                }
                : {}),
        });
        const defaults = (0, architectureComponentDiscoveryDefaults_1.resolveArchitectureWorkspaceDiscoveryDefaultsFromModel)(proposedModel);
        return {
            status: 'would_migrate_to_multi_component_structure',
            message: 'would migrate to multi-component structure',
            configPath,
            wouldWriteFiles: false,
            projectName: contract.projectName,
            repoTopology: contract.repoTopology,
            components: mapInferredComponents(inferredComponents),
            resources: mapInferredResources(inferredResources),
            inferredDefaults: mapDefaults(defaults.components),
            notes: ['Preview only: no files will be written.'],
        };
    }
    const defaults = (0, architectureComponentDiscoveryDefaults_1.resolveArchitectureWorkspaceDiscoveryDefaultsFromModel)(currentModel);
    return {
        status: 'no_changes_needed',
        message: 'no changes needed',
        configPath,
        wouldWriteFiles: false,
        projectName: contract.projectName,
        repoTopology: contract.repoTopology,
        components: mapModelComponents(currentModel),
        resources: mapModelResources(currentModel),
        inferredDefaults: mapDefaults(defaults.components),
        notes: ['Legacy single-project architecture config normalizes to one virtual workspace component.'],
    };
}
async function previewArchitectureMigration(workspaceRoot) {
    const configPath = path.join(workspaceRoot, '.archpilot', 'architecture.json');
    const contract = await (0, architectureInit_1.loadArchitectureContract)(workspaceRoot);
    if (!contract) {
        return {
            status: 'missing_config',
            message: 'architecture.json not found',
            configPath,
            wouldWriteFiles: false,
            components: [],
            resources: [],
            inferredDefaults: [],
            notes: ['Run ArchPilot initialization before previewing architecture migration.'],
        };
    }
    return buildArchitectureMigrationPreview(contract, configPath);
}
function renderList(values) {
    return values.length > 0 ? values.join(', ') : 'none';
}
function renderArchitectureMigrationPreviewText(preview) {
    const lines = [
        'ArchPilot architecture migration preview',
        `Config: ${preview.configPath}`,
        `Status: ${preview.message}`,
        'Files: no files will be written',
    ];
    if (preview.projectName) {
        lines.push(`Project: ${preview.projectName}`);
    }
    if (preview.repoTopology) {
        lines.push(`Topology: ${preview.repoTopology}`);
    }
    lines.push('', 'Components:');
    if (preview.components.length === 0) {
        lines.push('- none');
    }
    else {
        for (const component of preview.components) {
            const details = [
                component.path ? `path ${component.path}` : undefined,
                component.kind ? `kind ${component.kind}` : undefined,
                component.type ? `type ${component.type}` : undefined,
                component.stack ? `stack ${component.stack}` : undefined,
                `modules ${renderList(component.moduleIds)}`,
            ].filter((value) => !!value);
            lines.push(`- ${component.id} (${component.name}, ${component.source}): ${details.join('; ')}`);
        }
    }
    lines.push('', 'Resources:');
    if (preview.resources.length === 0) {
        lines.push('- none');
    }
    else {
        for (const resource of preview.resources) {
            const details = [
                resource.type ? `type ${resource.type}` : undefined,
                resource.provider ? `provider ${resource.provider}` : undefined,
                resource.ownerComponent ? `owner ${resource.ownerComponent}` : undefined,
                resource.path ? `path ${resource.path}` : undefined,
            ].filter((value) => !!value);
            lines.push(`- ${resource.id} (${resource.name}, ${resource.source}): ${details.join('; ')}`);
        }
    }
    lines.push('', 'Inferred defaults:');
    if (preview.inferredDefaults.length === 0) {
        lines.push('- none');
    }
    else {
        for (const defaults of preview.inferredDefaults) {
            lines.push(`- ${defaults.componentId}: adapter ${defaults.adapterId}; source roots ${renderList(defaults.sourceRoots)}; module roots ${renderList(defaults.moduleRoots)}; contracts ${defaults.contractPattern}; imports ${defaults.importExtractionMode}`);
        }
    }
    if (preview.notes.length > 0) {
        lines.push('', 'Notes:');
        for (const note of preview.notes) {
            lines.push(`- ${note}`);
        }
    }
    return `${lines.join('\n')}\n`;
}
//# sourceMappingURL=architectureMigrationPreview.js.map