    #include "templates.hpp"
    #include "config.hpp"   
    #include "utils/directories.hpp"
    #include "utils/utils.hpp"
    #include <filesystem>
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <algorithm>
    #include <iomanip>

    namespace dropshell {


    bool get_templates(std::vector<template_info>& templates) {
        templates.clear();
            
        // Helper function to add templates from a directory
        auto add_templates_from_dir = [&templates](const std::string& dir_path) {
            if (!std::filesystem::exists(dir_path)) 
                return;
            
            for (const auto& entry : std::filesystem::directory_iterator(dir_path)) 
                if (entry.is_directory()) {

                    template_info info(entry.path().filename().string(), entry.path().string());

                    // Check if template with same name already exists
                    bool duplicate = false;
                    auto it = std::find_if(templates.begin(), templates.end(),
                        [&info](const template_info& t) { return t.template_name == info.template_name; });
                    duplicate = (it!=templates.end());

                    if (!duplicate) 
                        templates.push_back(info);
                }
        };

        // add templates from the local config directories
        std::vector<std::string> template_config_directories;
        get_all_template_config_directories(template_config_directories);
        for (const auto& path : template_config_directories) {
            add_templates_from_dir(path);
        }
        
        return true;
    }


    bool get_template_info(const std::string& template_name, template_info& info) {
        // add templates from the local config directories
        std::vector<std::string> paths_to_search;
        get_all_template_config_directories(paths_to_search);

        for (const auto& path : paths_to_search) {
            std::filesystem::path full_path = path + "/" + template_name;
            if (std::filesystem::exists(full_path)) 
            {
                info.template_name = template_name;
                info.local_template_path = full_path.string();
                return true;
            }
        }
        std::cout << "Warning: Template '" << template_name << "' not found" << std::endl;
        return false;
    }

    bool template_command_exists(const std::string &template_name, const std::string &command)
    {
        template_info info;
        if (!get_template_info(template_name, info)) {
            return false;
        }
        
        std::string path = info.local_template_path + "/" + command + ".sh";
        return (std::filesystem::exists(path));
    }

    void list_templates() {
        std::vector<template_info> templates;
        
        if (!get_templates(templates)) {
            std::cerr << "Error: Failed to get templates" << std::endl;
            return;
        }
        
        if (templates.empty()) {
            std::cout << "No templates found." << std::endl;
            return;
        }
        
        std::cout << "Available templates:" << std::endl;
        std::cout << std::left << std::setw(20) << "Name" << "Path" << std::endl;
        std::cout << std::string(60, '-') << std::endl;
        
        for (const auto& t : templates) {
            std::cout << std::left << std::setw(20) << t.template_name << t.local_template_path << std::endl;
        }
    }

    void create_template(const std::string& template_name) {
        // 1. Create a new directory in the user templates directory
        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;
        }

        template_info info;
        if (get_template_info(template_name, info)) {
            std::cerr << "Error: Template '" << template_name << "' already exists at " << info.local_template_path << std::endl;
            return;
        }

        std::string new_template_path = localpath::config_templates() + "/" + template_name;
        
        // Create the new template directory
        std::filesystem::create_directories(new_template_path);
        
        // 2. Copy the example template from the system templates directory
        std::string system_templates_dir = localpath::system_templates();
        std::string example_template_path = system_templates_dir + "/example-nginx";
        
        if (!std::filesystem::exists(example_template_path)) {
            std::cerr << "Error: Example template not found at " << example_template_path << std::endl;
            return;
        }
        
        // Copy all files from example template to new template
        for (const auto& entry : std::filesystem::recursive_directory_iterator(example_template_path)) {
            std::string relative_path = entry.path().string().substr(example_template_path.length());
            std::string target_path = new_template_path + relative_path;
            
            if (entry.is_directory()) {
                std::filesystem::create_directory(target_path);
            } else {
                std::filesystem::copy_file(entry.path(), target_path);
            }
        }

        // modify the TEMPLATE=example line in the service.env file to TEMPLATE=<template_name>
        std::string search_string = "TEMPLATE=";
        std::string replacement_line = "TEMPLATE=" + template_name;
        // replace the line in the example/service.env file with the replacement line
        std::string service_env_path = new_template_path + "/example/service.env";
        if (!replace_line_in_file(service_env_path, search_string, replacement_line)) {
            std::cerr << "Error: Failed to replace TEMPLATE= line in service.env file" << std::endl;
            return;
        }

        // 3. Print out the README.txt file and the path
        std::string readme_path = new_template_path + "/README.txt";
        if (std::filesystem::exists(readme_path)) {
            std::cout << "\nREADME contents:" << std::endl;
            std::cout << std::string(60, '-') << std::endl;
            
            std::ifstream readme_file(readme_path);
            if (readme_file.is_open()) {
                std::string line;
                while (std::getline(readme_file, line)) {
                    std::cout << line << std::endl;
                }
                readme_file.close();
            }
            std::cout << std::string(60, '-') << std::endl;
        } else {
            std::cout << "No README.txt file found in the template." << std::endl;
        }

        std::cout << std::endl;
        std::cout << "Template '" << template_name << "' created at " << new_template_path << std::endl;
    }

    bool get_all_template_config_directories(std::vector<std::string> &template_config_directories)
    {
        template_config_directories.clear();
        for (int i = 0; i < localpath::num_config_directories(); i++) {
            std::string config_templates_path = localpath::config_templates(i);
            if (config_templates_path.empty()) {
                std::cerr << "Error: Templates directory not found: " << config_templates_path << std::endl;
                return false;
            }
            template_config_directories.push_back(config_templates_path);
        }
        template_config_directories.push_back(localpath::system_templates());
        return true;
    }

    } // namespace dropshell
