#include "services.hpp"
#include "utils/envmanager.hpp"
#include "utils/directories.hpp"
#include "templates.hpp"
#include "config.hpp"
#include "utils/utils.hpp"
#include "server_env_manager.hpp"
#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

namespace dropshell {   

std::vector<ServiceInfo> get_server_services_info(const std::string& server_name) {
    std::vector<ServiceInfo> services;

    if (server_name.empty())
        return services;

    std::vector<std::string> local_config_directories = gConfig().get_local_config_directories();
    if (local_config_directories.empty()) {
        std::cerr << "Error: No local config directories found" << std::endl;
        std::cerr << "Run 'dropshell init' to initialise DropShell" << std::endl;
        return services;
    }

    for (int i = 0; i < localpath::num_config_directories(); i++) {
        std::string serverpath = localpath::config_servers(i);
        if (serverpath.empty()) {
            std::cerr << "Error: Server directory not found: " << serverpath << std::endl;
            return services;
        }
        fs::path server_dir = fs::path(serverpath) / server_name;
        if (fs::exists(server_dir)) {
            for (const auto& entry : fs::directory_iterator(server_dir)) {
                if (fs::is_directory(entry)) {
                    ServiceInfo service = get_service_info(server_name, entry.path().filename().string());
                    if (!service.template_name.empty()) {
                        services.push_back(service);
                    }
                }
            }
        } // end of for (int i = 0; i < getNumConfigDirectories(); i++)
    }
    
   
    return services;
}


ServiceInfo get_service_info(const std::string &server_name, const std::string &service_name)
{
    ServiceInfo service;

    if (server_name.empty() || service_name.empty())
        return ServiceInfo();

    service.service_name = service_name;

    service.local_service_path = localpath::service(server_name, service_name);
    if (service.local_service_path.empty()) 
        return ServiceInfo();


    // now set the template name and path.
    std::string local_service_env_path = localfile::service_env(server_name, service_name);
    envmanager env(local_service_env_path);
    if (!env.load()) {
        if (std::filesystem::exists(localpath::service(server_name, service_name)))
            std::cerr << "Error: service malformed - service.env missing from " << local_service_env_path << std::endl;
        else
        {
            template_info tinfo;
            get_template_info(service_name, tinfo);
            std::string template_name = service_name;
            if (tinfo.local_template_path.empty())
                template_name = "TEMPLATE";
            std::cerr << "Error: you need to create that service first, with:  dropshell create-service " << server_name << " "<<template_name<<" " << service_name << std::endl;
        }
        return ServiceInfo();
    }
    service.template_name = env.get_variable("TEMPLATE");

    if (service.template_name.empty()) {
        std::cerr << "Error: TEMPLATE variable not defined in " << local_service_env_path << std::endl;
        return ServiceInfo();
    }

    template_info tinfo;
    if (!get_template_info(service.template_name, tinfo)) {
        std::cerr << "Error: Template '" << service.template_name << "' not found" << std::endl;
        return ServiceInfo();
    }

    // find the template path   
    service.local_template_path = tinfo.local_template_path;
    service.local_template_default_env_path = tinfo.local_template_path + "/_default.env";

    return service;
}

std::set<std::string> get_used_commands(const std::string &server_name, const std::string &service_name)
{
    std::set<std::string> commands;

    if (server_name.empty() || service_name.empty())
        return commands;

    ServiceInfo service_info = get_service_info(server_name, service_name);
    if (service_info.local_template_path.empty()) {
        std::cerr << "Error: Service not found: " << service_name << std::endl;
        return commands;
    }

    // iterate over all files in the template path, and add the command name to the set.
    // commands are .sh files that don't begin with _
    for (const auto& entry : fs::directory_iterator(service_info.local_template_path)) {
        if (fs::is_regular_file(entry) && entry.path().extension() == ".sh" && (entry.path().filename().string().rfind("_", 0) != 0)) 
            commands.insert(entry.path().stem().string());
    }
    return commands;
}

std::set<std::string> list_backups(const std::string &server_name, const std::string &service_name)
{
    std::set<std::string> backups;

    if (server_name.empty() || service_name.empty())
        return backups;

    // need to find the template for the service.
    ServiceInfo service_info = get_service_info(server_name, service_name);
    if (service_info.local_template_path.empty()) {
        std::cerr << "Error: Service not found: " << service_name << std::endl;
        return backups;
    }

    std::string backups_dir = localpath::backups_path();
    if (backups_dir.empty())
        return backups;

    if (fs::exists(backups_dir)) {
        for (const auto& entry : fs::directory_iterator(backups_dir)) {
            if (fs::is_regular_file(entry) && entry.path().extension() == ".tgz")
                if (entry.path().filename().string().find(service_info.template_name) != std::string::npos)
                {
                    backups.insert(entry.path().filename().string());
                }
        }
    }
    return backups;
}

bool create_service(const std::string &server_name, const std::string &template_name, const std::string &service_name, bool silent)
{
    if (server_name.empty() || template_name.empty() || service_name.empty())
        return false;

    std::string service_dir = localpath::service(server_name, service_name);

    if (service_dir.empty())
    {
        if (!silent)
        {
            std::cerr << "Error: Couldn't locate server " << server_name << " in any config directory" << std::endl;
            std::cerr << "Please check the server name is correct and try again" << std::endl;
            std::cerr << "You can list all servers with 'dropshell servers'" << std::endl;
            std::cerr << "You can create a new server with 'dropshell create-server " << server_name << "'" << std::endl;
        }
        return false;
    }

    if (fs::exists(service_dir)) 
    {
        if (!silent)
        {
            std::cerr << "Error: Service already exists: " << service_name << std::endl;
            std::cerr << "Current service path: " << service_dir << std::endl;
        }
        return false;
    }

    template_info tinfo;
    if (!get_template_info(template_name, tinfo))
    {
        if (!silent)
        {
            std::cerr << "Error: Template '" << template_name << "' not found" << std::endl;
            std::cerr << "Please check the template name is correct and try again" << std::endl;
            std::cerr << "You can list all templates with 'dropshell templates'" << std::endl;
            std::cerr << "You can create a new template with 'dropshell create-template " << template_name << "'" << std::endl;
        }
        return false;
    }
    
    // create the service directory
    fs::create_directory(service_dir);

    // copy the template example files to the service directory
    recursive_copy(tinfo.local_template_path+"/example", service_dir);

    if (!silent)
    {
        std::cout << "Service " << service_name <<" created successfully"<<std::endl;
        std::cout << std::endl;
        std::cout << "To complete the installation, please:" << std::endl;
        std::cout << "1. edit the service.env file:     dropshell edit " << server_name << " " << service_name << std::endl;
        std::cout << "2. install the remote service:    dropshell install " << server_name << " " << service_name << std::endl;
    }
    return true;
}

} // namespace dropshell
