// SPDX-License-Identifier: Apache-2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { inject, injectable } from 'tsyringe-neo';
import { InjectTokens } from '../../../../core/dependency-injection/inject-tokens.js';
import { LocalConfigSource } from '../../../../data/configuration/impl/local-config-source.js';
import { YamlFileStorageBackend } from '../../../../data/backend/impl/yaml-file-storage-backend.js';
import { patchInject } from '../../../../core/dependency-injection/container-helper.js';
import { ClassToObjectMapper } from '../../../../data/mapper/impl/class-to-object-mapper.js';
import { ConfigKeyFormatter } from '../../../../data/key/config-key-formatter.js';
import { LocalConfigSchemaDefinition } from '../../../../data/schema/migration/impl/local/local-config-schema-definition.js';
import { LocalConfigSchema } from '../../../../data/schema/model/local/local-config-schema.js';
import { RefreshLocalConfigSourceError } from '../../../errors/refresh-local-config-source-error.js';
import { WriteLocalConfigFileError } from '../../../errors/write-local-config-file-error.js';
import { PathEx } from '../../../utils/path-ex.js';
import fs, { existsSync, mkdirSync } from 'node:fs';
import { LocalConfig } from './local-config.js';
import path from 'node:path';
import { Templates } from '../../../../core/templates.js';
import { Flags as flags } from '../../../../commands/flags.js';
let LocalConfigRuntimeState = class LocalConfigRuntimeState {
    basePath;
    fileName;
    configManager;
    source;
    backend;
    objectMapper;
    isLoaded = false;
    _localConfig;
    constructor(basePath, fileName, configManager) {
        this.basePath = basePath;
        this.fileName = fileName;
        this.configManager = configManager;
        this.fileName = patchInject(fileName, InjectTokens.LocalConfigFileName, this.constructor.name);
        this.basePath = patchInject(basePath, InjectTokens.HomeDirectory, this.constructor.name);
        this.configManager = patchInject(configManager, InjectTokens.ConfigManager, this.constructor.name);
        this.backend = new YamlFileStorageBackend(this.basePath);
        this.objectMapper = new ClassToObjectMapper(ConfigKeyFormatter.instance());
        this.source = new LocalConfigSource(fileName, new LocalConfigSchemaDefinition(this.objectMapper), this.objectMapper, this.backend, LocalConfigSchema.EMPTY);
    }
    get configuration() {
        if (!this.isLoaded) {
            throw new Error('configuration: Local configuration is not loaded yet. Please call load() first.');
        }
        return this._localConfig;
    }
    // Loads the source data and writes it back in case of migrations.
    async load() {
        // TODO this needs to be a migration, not a load
        // check if config from an old version exists under the cache directory
        const oldConfigPath = PathEx.join(this.basePath, 'cache');
        const oldConfigFile = PathEx.join(oldConfigPath, this.fileName);
        const oldConfigFileExists = existsSync(oldConfigFile);
        if (this.configFileExists() && oldConfigFileExists) {
            // if both files exist, remove the old one
            fs.rmSync(oldConfigFile);
        }
        else if (existsSync(oldConfigFile)) {
            // if only the old file exists, copy it to the new location
            mkdirSync(this.basePath, { recursive: true });
            fs.copyFileSync(oldConfigFile, PathEx.join(this.basePath, this.fileName));
            fs.rmSync(oldConfigFile);
        }
        this.refresh();
        if (!this.configFileExists()) {
            return await this.persist();
        }
        try {
            await this.source.refresh();
            this.refresh();
        }
        catch (error) {
            throw new RefreshLocalConfigSourceError('Failed to refresh local config source', error);
        }
        await this.persist();
        await this.migrateCacheDirectories();
        this.isLoaded = true;
    }
    /**
     * Migrates the cache directories to the new structure.
     * It will look for directories in the format 'v0.58/staging/v0.58.10' and move them to current staging directory.
     */
    async migrateCacheDirectories() {
        if (!this.isLoaded) {
            throw new Error('migrateCacheDirectories: Local configuration is not loaded yet. Please call load() first.');
        }
        const cacheDirectory = PathEx.join(this.basePath, 'cache').toString();
        const releaseTag = this.configManager.getFlag(flags.releaseTag);
        const currentStagingDirectory = Templates.renderStagingDir(cacheDirectory, releaseTag);
        if (fs.existsSync(currentStagingDirectory)) {
            return;
        }
        // migrate the staging directory if it exists
        const foundStagingDirectory = await this.findMatchingSoloCacheDirectories(PathEx.join(this.basePath, 'cache').toString());
        if (foundStagingDirectory && foundStagingDirectory.length > 0) {
            for (const stagingDirectory of foundStagingDirectory) {
                fs.cpSync(stagingDirectory, currentStagingDirectory, { recursive: true, force: true });
                // remove the old staging directory
                fs.rmSync(stagingDirectory, { recursive: true, force: true });
            }
        }
    }
    async findMatchingSoloCacheDirectories(baseDirectory) {
        if (!this.isLoaded) {
            throw new Error('findMatchingSoloCacheDirectories: Local configuration is not loaded yet. Please call load() first.');
        }
        // Regex to match directory names like 'v0.58' or 'v0.60'
        // This will capture the version number.
        const versionDirectionRegex = /^v(\d+\.\d+)$/;
        // Regex to match the full path structure like 'v0.58/staging/v0.58.10'
        // This captures the major.minor version and the patch version.
        const fullPathRegex = /^v(\d+\.\d+)\/staging\/v(\d+\.\d+\.\d+)$/;
        const matchingDirectories = [];
        try {
            // 1. Read the contents of the baseCacheDir (e.g., '.solo/cache/')
            const versionDirectories = fs.readdirSync(baseDirectory);
            for (const versionDirectory of versionDirectories) {
                const versionMatch = versionDirectory.match(versionDirectionRegex);
                if (versionMatch) {
                    // If the version directory matches (e.g., 'v0.58')
                    const fullVersionPath = path.join(baseDirectory, versionDirectory, 'staging');
                    // Check if 'staging' directory exists within the version directory
                    if (fs.existsSync(fullVersionPath)) {
                        // Read the contents of the 'staging' directory
                        const stagingContents = fs.readdirSync(fullVersionPath);
                        for (const stagingItem of stagingContents) {
                            const fullItemPath = path.join(fullVersionPath, stagingItem);
                            const relativeItemPath = path.relative(baseDirectory, fullItemPath); // Get path relative to baseCacheDir
                            // Check if the full relative path matches the desired pattern
                            if (fullPathRegex.test(relativeItemPath) && fs.existsSync(fullItemPath)) {
                                matchingDirectories.push(fullItemPath);
                            }
                        }
                    }
                }
            }
        }
        catch {
            // The Directory isn't found or any other error
            return undefined;
        }
        return matchingDirectories;
    }
    async persist() {
        try {
            await this.source.persist();
            this.isLoaded = true;
        }
        catch (error) {
            throw new WriteLocalConfigFileError('Failed to write local config file', error);
        }
    }
    refresh() {
        this._localConfig = new LocalConfig(this.source.modelData);
    }
    configFileExists() {
        try {
            return fs.existsSync(PathEx.join(this.basePath, this.fileName));
        }
        catch {
            return false;
        }
    }
};
LocalConfigRuntimeState = __decorate([
    injectable(),
    __param(0, inject(InjectTokens.HomeDirectory)),
    __param(1, inject(InjectTokens.LocalConfigFileName)),
    __param(2, inject(InjectTokens.ConfigManager)),
    __metadata("design:paramtypes", [String, String, Function])
], LocalConfigRuntimeState);
export { LocalConfigRuntimeState };
//# sourceMappingURL=local-config-runtime-state.js.map