#include <iostream>
#include "parser.h"
#include "resolver.h"
#include "ir_gen.h"
#include "serializer.h"
#include <string>
#include <vector>
#include <cstring>

namespace nix_irc {

void print_usage(const char* prog) {
    std::cout << "Usage: " << prog << " [options] <input.nix> [output.nixir]\n"
              << "\nOptions:\n"
              << "  -I <path>    Add search path for imports\n"
              << "  --no-imports Disable import resolution\n"
              << "  --help       Show this help\n";
}

int run_compile(int argc, char** argv) {
    std::string input_file;
    std::string output_file;
    std::vector<std::string> search_paths;
    bool resolve_imports = true;
    
    int i = 1;
    while (i < argc) {
        std::string arg = argv[i];
        if (arg == "-I") {
            if (i + 1 >= argc) {
                std::cerr << "Error: -I requires a path argument\n";
                return 1;
            }
            search_paths.push_back(argv[++i]);
        } else if (arg == "--no-imports") {
            resolve_imports = false;
        } else if (arg == "--help" || arg == "-h") {
            print_usage(argv[0]);
            return 0;
        } else if (arg[0] != '-') {
            input_file = arg;
            if (i + 1 < argc && argv[i + 1][0] != '-') {
                output_file = argv[++i];
            }
        } else {
            std::cerr << "Unknown option: " << arg << "\n";
            print_usage(argv[0]);
            return 1;
        }
        i++;
    }
    
    if (input_file.empty()) {
        std::cerr << "Error: No input file specified\n";
        print_usage(argv[0]);
        return 1;
    }
    
    if (output_file.empty()) {
        output_file = input_file + "r";
    }
    
    try {
        Parser parser;
        Resolver resolver;
        
        for (const auto& path : search_paths) {
            resolver.add_search_path(path);
        }
        
        std::cout << "Parsing: " << input_file << "\n";
        auto ast = parser.parse_file(input_file);
        
        if (!ast) {
            std::cerr << "Error: Failed to parse input\n";
            return 1;
        }
        
        std::cout << "Resolving imports...\n";
        
        IRGenerator ir_gen;
        
        std::cout << "Generating IR...\n";
        auto ir = ir_gen.generate(ast);

        IRModule module;
        module.version = IR_VERSION;
        module.entry = ir;
        
        std::cout << "Serializing to: " << output_file << "\n";
        Serializer serializer;
        serializer.serialize(module, output_file);
        
        std::cout << "Done!\n";
        return 0;
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
        return 1;
    }
}

void print_decompile_usage(const char* prog) {
    std::cout << "Usage: " << prog << " decompile <input.nixir>\n";
}

int run_decompile(int argc, char** argv) {
    if (argc < 3) {
        print_decompile_usage(argv[0]);
        return 1;
    }
    
    std::string input_file = argv[2];
    
    try {
        Deserializer deserializer;
        auto module = deserializer.deserialize(input_file);
        
        std::cout << "IR Version: " << module.version << "\n";
        std::cout << "Sources: " << module.sources.size() << "\n";
        std::cout << "Imports: " << module.imports.size() << "\n";
        
        return 0;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
        return 1;
    }
}

}

int main(int argc, char** argv) {
    if (argc < 2) {
        nix_irc::print_usage(argv[0]);
        return 1;
    }
    
    std::string cmd = argv[1];
    
    if (cmd == "compile" || cmd == "c") {
        return nix_irc::run_compile(argc - 1, argv + 1);
    } else if (cmd == "decompile" || cmd == "d") {
        return nix_irc::run_decompile(argc, argv);
    } else if (cmd == "help" || cmd == "--help" || cmd == "-h") {
        nix_irc::print_usage(argv[0]);
        return 0;
    } else {
        return nix_irc::run_compile(argc, argv);
    }
}
