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

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 + "ir";
  }

  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;
  }
}

} // namespace nix_irc

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);
  }
}
