#include "resolver.h"
#include "parser.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <filesystem>
#include <regex>

namespace nix_irc {

namespace fs = std::filesystem;

struct Resolver::Impl {
    ResolverConfig config;
    std::vector<std::pair<std::string, std::string>> resolved_imports;
    std::unordered_set<std::string> visited;
    Parser parser;
    
    Impl(const ResolverConfig& cfg) : config(cfg) {}
    
    std::string resolve_path(const std::string& path, const std::string& from_file) {
        fs::path p(path);
        
        if (p.is_absolute()) {
            if (fs::exists(p)) return path;
            return "";
        }
        
        fs::path from_dir = fs::path(from_file).parent_path();
        fs::path candidate = from_dir / p;
        if (fs::exists(candidate)) return candidate.string();
        
        for (const auto& search : config.search_paths) {
            candidate = fs::path(search) / p;
            if (fs::exists(candidate)) return candidate.string();
        }
        
        return "";
    }
    
    ImportResult do_resolve(const std::string& path, const std::string& from_file) {
        std::string resolved = resolve_path(path, from_file);
        
        if (resolved.empty()) {
            return {false, "", "Cannot find file: " + path, nullptr};
        }
        
        if (visited.count(resolved)) {
            return {true, resolved, "", nullptr};
        }
        visited.insert(resolved);
        
        try {
            auto ast = parser.parse_file(resolved);
            return {true, resolved, "", ast};
        } catch (const std::exception& e) {
            return {false, "", e.what(), nullptr};
        }
    }
};

Resolver::Resolver(const ResolverConfig& config) : pImpl(std::make_unique<Impl>(config)) {}
Resolver::~Resolver() = default;

void Resolver::add_search_path(const std::string& path) {
    pImpl->config.search_paths.push_back(path);
}

void Resolver::set_search_paths(const std::vector<std::string>& paths) {
    pImpl->config.search_paths = paths;
}

ImportResult Resolver::resolve_import(const std::string& path, const std::string& from_file) {
    auto result = pImpl->do_resolve(path, from_file);
    if (result.success && result.ast) {
        pImpl->resolved_imports.push_back({path, result.path});
    }
    return result;
}

ImportResult Resolver::resolve_import(const Node& import_node, const std::string& from_file) {
    const ConstPathNode* path_node = import_node.get_if<ConstPathNode>();
    if (!path_node) {
        return {false, "", "Dynamic import not supported", nullptr};
    }
    return resolve_import(path_node->value, from_file);
}

std::vector<std::string> Resolver::get_resolved_files() const {
    std::vector<std::string> files;
    for (const auto& [orig, resolved] : pImpl->resolved_imports) {
        (void)orig;
        files.push_back(resolved);
    }
    return files;
}

std::vector<std::pair<std::string, std::string>> Resolver::get_imports() const {
    return pImpl->resolved_imports;
}

bool is_static_import(const Node& node) {
    return node.holds<ConstPathNode>();
}

std::string normalize_path(const std::string& path) {
    fs::path p(path);
    return fs::absolute(p).string();
}

}
