#include <fesa/analysis/run_solver.hpp>
#include <fesa/core/version.hpp>

#include <filesystem>
#include <iostream>
#include <string>
#include <string_view>

namespace {

std::string_view stage_name(const fesa::DiagnosticStage stage) {
    switch (stage) {
        case fesa::DiagnosticStage::io:
            return "io";
        case fesa::DiagnosticStage::syntax:
            return "syntax";
        case fesa::DiagnosticStage::semantic:
            return "semantic";
        case fesa::DiagnosticStage::model:
            return "model";
        case fesa::DiagnosticStage::equation:
            return "equation";
        case fesa::DiagnosticStage::solver:
            return "solver";
        case fesa::DiagnosticStage::results:
            return "results";
        case fesa::DiagnosticStage::validation:
            return "validation";
    }
    return "unknown";
}

void print_diagnostic(const fesa::Diagnostic& diagnostic) {
    std::cerr << stage_name(diagnostic.stage) << " [" << diagnostic.code
              << "]";
    if (diagnostic.source.has_value()) {
        const fesa::SourceLocation& source = *diagnostic.source;
        std::cerr << ' ' << source.file.string() << ':' << source.line << ':'
                  << source.column;
    }
    std::cerr << ": " << diagnostic.message << '\n';
}

void print_usage() {
    std::cerr << "Usage:\n"
              << "  fesa solve <model.inp> --output <results.h5>\n"
              << "  fesa --version\n";
}

}  // namespace

int main(int argc, char* argv[]) {
    if (argc == 2 && std::string_view{argv[1]} == "--version") {
        std::cout << fesa::version() << '\n';
        return 0;
    }

    if (argc == 5 && std::string_view{argv[1]} == "solve" &&
        std::string_view{argv[3]} == "--output") {
        const fesa::AnalysisRunResult result = fesa::run_solver({
            std::filesystem::path{argv[2]},
            std::filesystem::path{argv[4]},
        });
        if (result.succeeded) {
            return 0;
        }
        for (const fesa::Diagnostic& diagnostic : result.diagnostics) {
            print_diagnostic(diagnostic);
        }
        return 1;
    }

    print_usage();
    return 1;
}
