// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

import {existsSync, mkdirSync, writeFileSync, readFileSync} from "fs";

/**
 * Synchronizes deployment information by saving the provided package and deployment data
 * to a persisted `.ops/deployment.json` file. If the directory `.ops` does not exist, it
 * is created before saving the information.
 *
 * The deployment information is organized by packages, with each package containing an array
 * of its actions. This allows for more granular control when undeploying specific actions.
 *
 * @param {Set<string>} packages - A set of package names to include in the deployment data.
 * @param {Set<string>} deployments - A set of deployment identifiers to include in the deployment data.
 * @return {void}
 */
export function syncDeployInfo(packages, deployments) {
    if (!existsSync('.ops')) {
        mkdirSync('.ops', { recursive: true });
    }

    // Create a structured object with packages as keys and arrays of actions as values
    const packageActions = {};

    // Initialize packages with empty arrays
    for (const pkg of packages) {
        packageActions[pkg] = [];
    }

    // Add actions to their respective packages
    for (const deployment of deployments) {
        try {
            const sp = deployment.split("/");
            const spData = sp[sp.length - 1].split(".");
            const name = spData[0];
            const pkg = sp[1];

            // If the package exists in our structure, add the action to it
            if (packageActions[pkg]) {
                packageActions[pkg].push(name);
            }
        } catch (error) {
            console.error(`Error parsing deployment path ${deployment}:`, error);
        }
    }

    const deploymentInfo = {
        packages: Array.from(packages),
        packageActions: packageActions
    };

    writeFileSync('.ops/deployment.json', JSON.stringify(deploymentInfo, null, 2));
    console.log("> Saved deployment information to .ops/deployment.json");
}

/**
 * Removes a specific action from the deployment information.
 * 
 * @param {string} actionName - The name of the action to remove in the format "package/action".
 * @return {boolean} - True if the action was found and removed, false otherwise.
 */
export function removeActionFromDeployInfo(actionName) {
    if (!existsSync('.ops/deployment.json')) {
        console.error('Error: No deployment information found.');
        return false;
    }

    try {
        const deploymentInfo = JSON.parse(readFileSync('.ops/deployment.json', 'utf8'));
        const [pkg, action] = actionName.split('/');

        if (!deploymentInfo.packageActions || !deploymentInfo.packageActions[pkg]) {
            console.error(`❌ Error: Package ${pkg} not found in deployment information.`);
            return false;
        }

        const actionIndex = deploymentInfo.packageActions[pkg].indexOf(action);
        if (actionIndex === -1) {
            console.error(`❌ Error: Action ${action} not found in package ${pkg}.`);
            return false;
        }

        // Remove the action from the package
        deploymentInfo.packageActions[pkg].splice(actionIndex, 1);

        // If the package has no more actions, remove it from the packages list
        if (deploymentInfo.packageActions[pkg].length === 0) {
            const packageIndex = deploymentInfo.packages.indexOf(pkg);
            if (packageIndex !== -1) {
                deploymentInfo.packages.splice(packageIndex, 1);
            }
            delete deploymentInfo.packageActions[pkg];
        }

        writeFileSync('.ops/deployment.json', JSON.stringify(deploymentInfo, null, 2));
        console.log(`> Removed ${actionName} from deployment information.`);
        return true;
    } catch (error) {
        console.error("❌ Error updating deployment information:", error);
        return false;
    }
}

/**
 * Cleans up deployment information by resetting and synchronizing deployment data.
 */
export function cleanupDeployInfo() {
    syncDeployInfo(new Set(), new Set());
}
