// See https://aka.ms/new-console-template for more information
using eSuite.Translator;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;

var http = new HttpClient
{
    Timeout = TimeSpan.FromSeconds(600),
    BaseAddress = new Uri("http://aipi.cluster.local:11434")
};
var translator = new OllamaTranslationService(http);

LanguagePack LoadDictionary(string rootpath, string foldername)
{
    var path = Path.Combine(rootpath, foldername);
    //var files = Directory.GetFiles(path, "*.json", SearchOption.AllDirectories);
    var files = Directory
        .EnumerateFiles(path)
        .Where(f => f.EndsWith(".json", StringComparison.OrdinalIgnoreCase)
                    || f.EndsWith(".lang", StringComparison.OrdinalIgnoreCase));


    var languagePack = new LanguagePack();

    //load the master files into memory, 
    foreach (var file in files)
    {
        if (Path.GetExtension(file).ToLower() == ".lang")
        {
            languagePack.Locale = Path.GetFileNameWithoutExtension(file);
            continue;
        }

        var relativePath = Path.GetRelativePath(path, file);
        var json = File.ReadAllText(file);
        var jsonDocument = JsonNode.Parse(json);

        languagePack.Files[Path.GetFileName(file)] = jsonDocument;
    }
    
    return languagePack;
}

void SaveDictionary(string rootpath, string foldername, Dictionary<string, JsonNode> dictionary)
{
    var folderPath = Path.Combine(rootpath, foldername);
    foreach (var item in dictionary)
    {
        var filename = item.Key;
        var path = Path.Combine(folderPath, filename);
        var sorted = SortJson(item.Value);
        File.WriteAllText(path, sorted.ToJsonString(new JsonSerializerOptions
        {
            WriteIndented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
        }));
    }
    Console.WriteLine($"{folderPath} saved");
}

async Task ReconcileNode(JsonNode masterNode, JsonNode languageNode, string targetLanguage)
{
    // If the master node is a value, nothing to recurse into
    if (masterNode is JsonValue)
        return;

    // If the master node is an object, ensure the language node is also an object
    if (masterNode is JsonObject masterObj)
    {
        var langObj = languageNode as JsonObject
                      ?? throw new InvalidOperationException("Language node must be an object here");

        foreach (var kvp in masterObj)
        {
            var key = kvp.Key;
            var masterChild = kvp.Value!;

            // If the language is missing this key, create a placeholder
            if (!langObj.TryGetPropertyValue(key, out var langChild))
            {
                // If master is a value → create empty string
                if (masterChild is JsonValue)
                {
                    var sourceText = masterChild.ToString();
                    var translated = await translator.TranslateAsync(sourceText, targetLanguage);
                    if (!translated.Equals(sourceText, StringComparison.InvariantCultureIgnoreCase))
                        langChild = JsonValue.Create(translated);
                    else
                        langChild = null;
                }
                else
                {
                    // If master is an object → create empty object
                    langChild = new JsonObject();
                }

                if (langChild != null)
                    langObj[key] = langChild;
            }

            // Recurse into children
            if (masterChild is JsonObject)
                await ReconcileNode(masterChild, langChild!, targetLanguage);
        }
    }
}

async Task ReconcileDictionary(Dictionary<string, JsonNode> languageDictionary, Dictionary<string, JsonNode> masterDictionary, string targetLanguage)
{
    foreach (var kvp in masterDictionary)
    {
        var filename = kvp.Key;
        var masterJson = kvp.Value;

        // Does the language folder have this file?
        if (!languageDictionary.TryGetValue(filename, out var langJson))
        {
            langJson = new JsonObject();
            languageDictionary[filename] = langJson;

        }

        // Reconcile the tree structure
        await ReconcileNode(masterJson, langJson, targetLanguage);
    }
}

static JsonNode SortJson(JsonNode node)
{
    switch (node)
    {
        case JsonObject obj:
        {
            var sorted = new JsonObject();

            foreach (var kvp in obj.OrderBy(k => k.Key, StringComparer.Ordinal))
            {
                // Clone before sorting to avoid parent conflicts
                var cloned = kvp.Value?.DeepClone();
                sorted[kvp.Key] = SortJson(cloned!);
            }

            return sorted;
        }

        case JsonArray arr:
        {
            var newArr = new JsonArray();
            foreach (var item in arr)
            {
                var cloned = item?.DeepClone();
                newArr.Add(SortJson(cloned!));
            }
            return newArr;
        }

        default:
            return node.DeepClone(); // primitives
    }
}


Console.WriteLine("Starting translation reconciliation");

const string rootpath = @"C:\Code\Gitea\e-suite\e-suite.webui\public\locales";

var masterDictionary = LoadDictionary(rootpath, "en");
SaveDictionary(rootpath, "en", masterDictionary.Files);

Console.WriteLine("Master files loaded");

var rootDir = new DirectoryInfo(rootpath);
var folders = rootDir.GetDirectories().Select(x => x.Name ).ToList();
folders.Remove("en"); //Ignore the master folder

var languageFolders = folders.Where(x => !x.Contains("-")).ToList();
var localeFolders = folders.Where(x => x.Contains("-")).ToList();

foreach ( var language in languageFolders)
{  
    var languageDictionary = LoadDictionary(rootpath, language);

    await ReconcileDictionary(languageDictionary.Files, masterDictionary.Files, languageDictionary.Locale);
    SaveDictionary(rootpath, language, languageDictionary.Files);
}


Console.WriteLine("Main Language files completed.");



public class LanguagePack
{
    public string Locale { get; set; }
    public Dictionary<string, JsonNode> Files { get; set; } = new();
}