#include "pch.h"
#include "Extensions/Logging/LoggerConfiguration.h"
#include "System/IO/File.h"
#include "System/IOException.h"
#include "System/ArgumentException.h"
#include "System/Text/Json/JsonSerializer.h"
#include "System/Text/Json/JsonException.h"

namespace {
    using namespace DotNetDupe::System;
    using namespace DotNetDupe::System::Text::Json;

    bool TryGetPropertyCaseInsensitive(const JsonElement& element, const String& targetName, JsonElement& outProp) {
        if (element.TryGetProperty(targetName, outProp)) {
            return true;
        }

        auto normalize = [](const String& s) {
            String lower = s.ToLower();
            const char* raw = lower.GetRawString();
            std::string cleaned;
            if (raw) {
                for (int i = 0; raw[i] != '\0'; ++i) {
                    if (raw[i] != '_') {
                        cleaned += raw[i];
                    }
                }
            }
            return String(cleaned.c_str());
        };

        String targetNormalized = normalize(targetName);

        auto propNames = element.GetPropertyNames();
        for (int i = 0; i < propNames.GetLength(); ++i) {
            if (normalize(propNames[i]) == targetNormalized) {
                return element.TryGetProperty(propNames[i], outProp);
            }
        }
        return false;
    }
}

namespace DotNetDupe {
    namespace System {
        namespace Text {
            namespace Json {

                template <>
                struct JsonConverter<DotNetDupe::Extensions::Logging::FileRolloverConfig> {
                    static JsonElement Write(const DotNetDupe::Extensions::Logging::FileRolloverConfig& value) {
                        JsonElement obj(JsonValueKind::Object);
                        obj.SetProperty("EnableRollover", JsonConverter<bool>::Write(value.EnableRollover));
                        obj.SetProperty("MaxFileSizeInBytes", JsonConverter<long long>::Write(value.MaxFileSizeInBytes));
                        obj.SetProperty("MaxBackupFiles", JsonConverter<int>::Write(value.MaxBackupFiles));
                        return obj;
                    }

                    static DotNetDupe::Extensions::Logging::FileRolloverConfig Read(const JsonElement& element) {
                        if (element.GetValueKind() != JsonValueKind::Object) {
                            throw JsonException("Expected a JSON object for FileRolloverConfig");
                        }
                        DotNetDupe::Extensions::Logging::FileRolloverConfig config;
                        JsonElement prop;
                        if (TryGetPropertyCaseInsensitive(element, "EnableRollover", prop)) {
                            config.EnableRollover = JsonConverter<bool>::Read(prop);
                        }
                        if (TryGetPropertyCaseInsensitive(element, "MaxFileSizeInBytes", prop)) {
                            config.MaxFileSizeInBytes = JsonConverter<long long>::Read(prop);
                        }
                        if (TryGetPropertyCaseInsensitive(element, "MaxBackupFiles", prop)) {
                            config.MaxBackupFiles = JsonConverter<int>::Read(prop);
                        }
                        return config;
                    }
                };

                template <>
                struct JsonConverter<DotNetDupe::Extensions::Logging::LoggerConfiguration> {
                    static JsonElement Write(const DotNetDupe::Extensions::Logging::LoggerConfiguration& value) {
                        JsonElement obj(JsonValueKind::Object);
                        String minLevelStr;
                        switch (value.MinLevel) {
                            case DotNetDupe::Extensions::Logging::LogLevel::Trace: minLevelStr = "Trace"; break;
                            case DotNetDupe::Extensions::Logging::LogLevel::Debug: minLevelStr = "Debug"; break;
                            case DotNetDupe::Extensions::Logging::LogLevel::Information: minLevelStr = "Information"; break;
                            case DotNetDupe::Extensions::Logging::LogLevel::Warning: minLevelStr = "Warning"; break;
                            case DotNetDupe::Extensions::Logging::LogLevel::Error: minLevelStr = "Error"; break;
                            case DotNetDupe::Extensions::Logging::LogLevel::Critical: minLevelStr = "Critical"; break;
                            case DotNetDupe::Extensions::Logging::LogLevel::None: minLevelStr = "None"; break;
                            default: minLevelStr = "Information"; break;
                        }
                        obj.SetProperty("MinLevel", JsonConverter<String>::Write(minLevelStr));
                        obj.SetProperty("IsJsonFormat", JsonConverter<bool>::Write(value.IsJsonFormat));
                        obj.SetProperty("PlainTextFormat", JsonConverter<String>::Write(value.PlainTextFormat));
                        obj.SetProperty("TimestampFormat", JsonConverter<String>::Write(value.TimestampFormat));
                        obj.SetProperty("FilePath", JsonConverter<String>::Write(value.FilePath));
                        obj.SetProperty("Rollover", JsonConverter<DotNetDupe::Extensions::Logging::FileRolloverConfig>::Write(value.Rollover));
                        return obj;
                    }

                    static DotNetDupe::Extensions::Logging::LoggerConfiguration Read(const JsonElement& element) {
                        if (element.GetValueKind() != JsonValueKind::Object) {
                            throw JsonException("Expected a JSON object for LoggerConfiguration");
                        }
                        DotNetDupe::Extensions::Logging::LoggerConfiguration config;
                        JsonElement prop;
                        if (TryGetPropertyCaseInsensitive(element, "MinLevel", prop)) {
                            if (prop.GetValueKind() == JsonValueKind::Number) {
                                int val = JsonConverter<int>::Read(prop);
                                config.MinLevel = static_cast<DotNetDupe::Extensions::Logging::LogLevel>(val);
                            } else if (prop.GetValueKind() == JsonValueKind::String) {
                                config.MinLevel = DotNetDupe::Extensions::Logging::ParseLogLevel(JsonConverter<String>::Read(prop));
                            } else {
                                throw JsonException("Invalid type for MinLevel in LoggerConfiguration");
                            }
                        }
                        if (TryGetPropertyCaseInsensitive(element, "IsJsonFormat", prop)) {
                            config.IsJsonFormat = JsonConverter<bool>::Read(prop);
                        }
                        if (TryGetPropertyCaseInsensitive(element, "PlainTextFormat", prop)) {
                            config.PlainTextFormat = JsonConverter<String>::Read(prop);
                        }
                        if (TryGetPropertyCaseInsensitive(element, "TimestampFormat", prop)) {
                            config.TimestampFormat = JsonConverter<String>::Read(prop);
                        }
                        if (TryGetPropertyCaseInsensitive(element, "FilePath", prop)) {
                            config.FilePath = JsonConverter<String>::Read(prop);
                        }
                        if (TryGetPropertyCaseInsensitive(element, "Rollover", prop)) {
                            config.Rollover = JsonConverter<DotNetDupe::Extensions::Logging::FileRolloverConfig>::Read(prop);
                        }
                        return config;
                    }
                };

            }
        }
    }
}

namespace DotNetDupe {
    namespace Extensions {
        namespace Logging {

            LogLevel ParseLogLevel(const DotNetDupe::System::String& str) {
                DotNetDupe::System::String lower = str.ToLower();
                if (lower == "trace") return LogLevel::Trace;
                if (lower == "debug") return LogLevel::Debug;
                if (lower == "information" || lower == "info") return LogLevel::Information;
                if (lower == "warning" || lower == "warn") return LogLevel::Warning;
                if (lower == "error") return LogLevel::Error;
                if (lower == "critical") return LogLevel::Critical;
                if (lower == "none") return LogLevel::None;

                if (lower == "0") return LogLevel::Trace;
                if (lower == "1") return LogLevel::Debug;
                if (lower == "2") return LogLevel::Information;
                if (lower == "3") return LogLevel::Warning;
                if (lower == "4") return LogLevel::Error;
                if (lower == "5") return LogLevel::Critical;
                if (lower == "6") return LogLevel::None;

                throw DotNetDupe::System::ArgumentException("Invalid LogLevel value");
            }

            LoggerConfiguration LoggerConfiguration::LoadFromFile(const DotNetDupe::System::String& filePath) {
                if (!DotNetDupe::System::IO::File::Exists(filePath)) {
                    throw DotNetDupe::System::IO::IOException("File does not exist");
                }
                DotNetDupe::System::String jsonContent = DotNetDupe::System::IO::File::ReadAllText(filePath);
                return LoadFromJson(jsonContent);
            }

            LoggerConfiguration LoggerConfiguration::LoadFromJson(const DotNetDupe::System::String& jsonContent) {
                return DotNetDupe::System::Text::Json::JsonSerializer::Deserialize<LoggerConfiguration>(jsonContent);
            }

        }
    }
}

Generated by OpenCppCoverage (Version: 0.9.9.0)