#include "app_core/document_route.h"

#include <cctype>
#include <utility>

namespace pp::app {
namespace {

[[nodiscard]] bool is_extension_char(char value) noexcept
{
    const auto ch = static_cast<unsigned char>(value);
    return std::isalnum(ch) != 0 || value == '_';
}

[[nodiscard]] std::string lowercase_ascii(std::string_view value)
{
    std::string lowered;
    lowered.reserve(value.size());
    for (const char ch : value) {
        lowered.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(ch))));
    }
    return lowered;
}

}

pp::foundation::Result<DocumentOpenRoute> classify_document_open_path(std::string_view path)
{
    const auto separator = path.find_last_of("/\\");
    if (separator == std::string_view::npos || separator + 1U >= path.size()) {
        return pp::foundation::Result<DocumentOpenRoute>::failure(
            pp::foundation::Status::invalid_argument("document path must include a directory and file name"));
    }

    const auto dot = path.find_last_of('.');
    if (dot == std::string_view::npos || dot <= separator + 1U || dot + 1U >= path.size()) {
        return pp::foundation::Result<DocumentOpenRoute>::failure(
            pp::foundation::Status::invalid_argument("document path must include a file extension"));
    }

    const std::string_view extension = path.substr(dot + 1U);
    for (const char ch : extension) {
        if (!is_extension_char(ch)) {
            return pp::foundation::Result<DocumentOpenRoute>::failure(
                pp::foundation::Status::invalid_argument("document extension contains unsupported characters"));
        }
    }

    auto lowered_extension = lowercase_ascii(extension);
    auto kind = DocumentOpenKind::open_project;
    if (lowered_extension == "abr") {
        kind = DocumentOpenKind::import_abr;
    } else if (lowered_extension == "ppbr") {
        kind = DocumentOpenKind::import_ppbr;
    }

    return pp::foundation::Result<DocumentOpenRoute>::success(
        DocumentOpenRoute {
            .kind = kind,
            .path = std::string(path),
            .directory = std::string(path.substr(0U, separator)),
            .name = std::string(path.substr(separator + 1U, dot - separator - 1U)),
            .extension = std::move(lowered_extension),
        });
}

}
