using AuthorBuddy.Web.Data;
using AuthorBuddy.Web.Models;
using LiteDB;

namespace AuthorBuddy.Web.Services;

public class SettingsService : ISettingsService
{
    private const string KeyOllamaUrl = "ollama_url";
    private const string KeyLlamaCppUrl = "llama_cpp_url";
    private const string KeyBackend = "llm_backend";
    private const string KeyRagModel = "ollama_rag_model";
    private const string KeyStyleModel = "ollama_style_model";
    private const string KeySpellingModel = "ollama_spelling_model";
    private const string KeyTheme = "theme";
    private const string KeyLektorPrompt = "ollama_lektor_prompt";
    private const string KeyFactCheckTemplate = "ollama_fact_check";
    private const string KeySpellingPrompt = "ollama_spelling_prompt";
    private const string KeyAdvocatusDiaboli = "ollama_advocatus_diaboli";
    private const string KeyHookFinder = "ollama_hook_finder";
    private const string KeyEli5 = "ollama_eli5";
    private const string KeyCoAuthor = "ollama_coauthor";
    private const string KeyLektorTemp = "ollama_lektor_temp";
    private const string KeyFactCheckTemp = "ollama_fact_check_temp";
    private const string KeySpellingTemp = "ollama_spelling_temp";
    private const string KeyAdvocatusDiaboliTemp = "ollama_advocatus_diaboli_temp";
    private const string KeyHookFinderTemp = "ollama_hook_finder_temp";
    private const string KeyEli5Temp = "ollama_eli5_temp";
    private const string KeyCoAuthorTemp = "ollama_coauthor_temp";
    private const string KeyTechLastenheft = "tech_lastenheft";
    private const string KeyTechPflichtenheft = "tech_pflichtenheft";
    private const string KeyTechUseCase = "tech_usecase";
    private const string KeyTechStakeholder = "tech_stakeholder";
    private const string KeyTechGlossar = "tech_glossar";
    private const string KeyTechQualitaet = "tech_qualitaet";
    private const string KeyTechRisiko = "tech_risiko";
    private const string KeyTechLastenheftTemp = "tech_lastenheft_temp";
    private const string KeyTechPflichtenheftTemp = "tech_pflichtenheft_temp";
    private const string KeyTechUseCaseTemp = "tech_usecase_temp";
    private const string KeyTechStakeholderTemp = "tech_stakeholder_temp";
    private const string KeyTechGlossarTemp = "tech_glossar_temp";
    private const string KeyTechQualitaetTemp = "tech_qualitaet_temp";
    private const string KeyTechRisikoTemp = "tech_risiko_temp";
    private const string KeyLanguage = "language";

    private const string KeyLastProjectId = "last_project_id";

    private readonly ILiteDatabase _db;
    private readonly OllamaSettings _ollamaConfig;
    private int? _currentUserId;
    private int? _currentProjectId;

    public SettingsService(ILiteDatabase db, OllamaSettings ollamaConfig)
    {
        _db = db;
        _ollamaConfig = ollamaConfig;
    }

    public int? CurrentProjectId
    {
        get => _currentProjectId;
        set => _currentProjectId = value;
    }

    public string? CurrentFilePath { get; set; }
    public string? PendingAssistantInput { get; set; }
    public string? PendingAssistantOutput { get; set; }

    public Task<int?> GetLastProjectIdAsync()
    {
        var col = _db.GetCollection<SettingEntity>("settings");
        var setting = col.FindOne(s => s.Key == KeyLastProjectId && s.UserId == _currentUserId && s.ProjectId == null);
        if (setting != null && int.TryParse(setting.Value, out var id))
            return Task.FromResult<int?>(id);
        return Task.FromResult<int?>(null);
    }

    public Task SaveLastProjectIdAsync(int projectId)
    {
        var col = _db.GetCollection<SettingEntity>("settings");
        var existing = col.FindOne(s => s.Key == KeyLastProjectId && s.UserId == _currentUserId && s.ProjectId == null);
        if (existing != null)
        {
            existing.Value = projectId.ToString();
            col.Update(existing);
        }
        else
        {
            col.Insert(new SettingEntity
            {
                Key = KeyLastProjectId,
                Value = projectId.ToString(),
                UserId = _currentUserId,
                ProjectId = null
            });
        }
        return Task.CompletedTask;
    }

    private string? GetSetting(string key, int? userId, int? projectId)
    {
        var col = _db.GetCollection<SettingEntity>("settings");

        var matches = col.Find(s =>
            s.Key == key &&
            (s.UserId == userId || s.UserId == null) &&
            (s.ProjectId == projectId || s.ProjectId == null));

        return matches
            .OrderByDescending(s => s.UserId != null)
            .ThenByDescending(s => s.ProjectId != null)
            .FirstOrDefault()?.Value;
    }

    private string? Get(string key)
    {
        return GetSetting(key, _currentUserId, _currentProjectId);
    }

    private string? GetGlobal(string key)
    {
        var col = _db.GetCollection<SettingEntity>("settings");
        return col.FindOne(s => s.Key == key && s.UserId == null && s.ProjectId == null)?.Value;
    }

    private void SetGlobal(string key, string value)
    {
        var col = _db.GetCollection<SettingEntity>("settings");
        var existing = col.FindOne(s => s.Key == key && s.UserId == null && s.ProjectId == null);
        if (existing != null)
        {
            existing.Value = value;
            col.Update(existing);
        }
        else
        {
            col.Insert(new SettingEntity { Key = key, Value = value, UserId = null, ProjectId = null });
        }
    }

    private void Set(string key, string value)
    {
        var col = _db.GetCollection<SettingEntity>("settings");

        var existing = col.FindOne(s =>
            s.Key == key && s.UserId == _currentUserId && s.ProjectId == null);

        if (existing != null)
        {
            existing.Value = value;
            col.Update(existing);
        }
        else
        {
            col.Insert(new SettingEntity
            {
                Key = key,
                Value = value,
                UserId = _currentUserId,
                ProjectId = null
            });
        }
    }

    public Task<string?> GetOllamaUrlAsync() => Task.FromResult(GetGlobal(KeyOllamaUrl));
    public Task<string?> GetLlamaCppUrlAsync() => Task.FromResult(GetGlobal(KeyLlamaCppUrl));
    public Task<string?> GetBackendAsync() => Task.FromResult(GetGlobal(KeyBackend));
    public Task<string?> GetRagModelAsync() => Task.FromResult(GetGlobal(KeyRagModel));
    public Task<string?> GetStyleModelAsync() => Task.FromResult(GetGlobal(KeyStyleModel));
    public Task<string?> GetLektorSystemPromptAsync() => Task.FromResult(Get(KeyLektorPrompt));
    public Task<string?> GetFactCheckTemplateAsync() => Task.FromResult(Get(KeyFactCheckTemplate));
    public Task<string?> GetSpellingPromptAsync() => Task.FromResult(Get(KeySpellingPrompt));
    public Task<string?> GetSpellingModelAsync() => Task.FromResult(GetGlobal(KeySpellingModel));
    public Task<string?> GetAdvocatusDiaboliPromptAsync() => Task.FromResult(Get(KeyAdvocatusDiaboli));
    public Task<string?> GetHookFinderPromptAsync() => Task.FromResult(Get(KeyHookFinder));
    public Task<string?> GetEli5PromptAsync() => Task.FromResult(Get(KeyEli5));
    public Task<string?> GetCoAuthorBrainstormingPromptAsync() => Task.FromResult(Get(KeyCoAuthor));
    public Task<double> GetLektorTempAsync() => Task.FromResult(double.TryParse(Get(KeyLektorTemp), out var v) ? v : _ollamaConfig.LektorTemp);
    public Task<double> GetFactCheckTempAsync() => Task.FromResult(double.TryParse(Get(KeyFactCheckTemp), out var v) ? v : _ollamaConfig.FactCheckTemp);
    public Task<double> GetSpellingTempAsync() => Task.FromResult(double.TryParse(Get(KeySpellingTemp), out var v) ? v : _ollamaConfig.SpellingTemp);
    public Task<double> GetAdvocatusDiaboliTempAsync() => Task.FromResult(double.TryParse(Get(KeyAdvocatusDiaboliTemp), out var v) ? v : _ollamaConfig.AdvocatusDiaboliTemp);
    public Task<double> GetHookFinderTempAsync() => Task.FromResult(double.TryParse(Get(KeyHookFinderTemp), out var v) ? v : _ollamaConfig.HookFinderTemp);
    public Task<double> GetEli5TempAsync() => Task.FromResult(double.TryParse(Get(KeyEli5Temp), out var v) ? v : _ollamaConfig.Eli5Temp);
    public Task<double> GetCoAuthorTempAsync() => Task.FromResult(double.TryParse(Get(KeyCoAuthorTemp), out var v) ? v : _ollamaConfig.CoAuthorTemp);

    public Task<string?> GetTechLastenheftPromptAsync() => Task.FromResult(Get(KeyTechLastenheft));
    public Task<string?> GetTechPflichtenheftPromptAsync() => Task.FromResult(Get(KeyTechPflichtenheft));
    public Task<string?> GetTechUseCasePromptAsync() => Task.FromResult(Get(KeyTechUseCase));
    public Task<string?> GetTechStakeholderPromptAsync() => Task.FromResult(Get(KeyTechStakeholder));
    public Task<string?> GetTechGlossarPromptAsync() => Task.FromResult(Get(KeyTechGlossar));
    public Task<string?> GetTechQualitaetPromptAsync() => Task.FromResult(Get(KeyTechQualitaet));
    public Task<string?> GetTechRisikoPromptAsync() => Task.FromResult(Get(KeyTechRisiko));
    public Task<double> GetTechLastenheftTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechLastenheftTemp), out var v) ? v : _ollamaConfig.TechLastenheftTemp);
    public Task<double> GetTechPflichtenheftTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechPflichtenheftTemp), out var v) ? v : _ollamaConfig.TechPflichtenheftTemp);
    public Task<double> GetTechUseCaseTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechUseCaseTemp), out var v) ? v : _ollamaConfig.TechUseCaseTemp);
    public Task<double> GetTechStakeholderTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechStakeholderTemp), out var v) ? v : _ollamaConfig.TechStakeholderTemp);
    public Task<double> GetTechGlossarTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechGlossarTemp), out var v) ? v : _ollamaConfig.TechGlossarTemp);
    public Task<double> GetTechQualitaetTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechQualitaetTemp), out var v) ? v : _ollamaConfig.TechQualitaetTemp);
    public Task<double> GetTechRisikoTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechRisikoTemp), out var v) ? v : _ollamaConfig.TechRisikoTemp);
    public Task<string?> GetThemeAsync() => Task.FromResult(Get(KeyTheme));
    public Task<string?> GetLanguageAsync() => Task.FromResult(Get(KeyLanguage));
    public Task SaveLanguageAsync(string language)
    {
        Set(KeyLanguage, language);
        _ollamaConfig.Language = language;
        return Task.CompletedTask;
    }

    public Task SaveOllamaUrlAsync(string url)
    {
        SetGlobal(KeyOllamaUrl, url);
        _ollamaConfig.OllamaUrl = url;
        return Task.CompletedTask;
    }

    public Task SaveLlamaCppUrlAsync(string url)
    {
        SetGlobal(KeyLlamaCppUrl, url);
        _ollamaConfig.LlamaCppUrl = url;
        return Task.CompletedTask;
    }

    public Task SaveBackendAsync(string backend)
    {
        SetGlobal(KeyBackend, backend);
        _ollamaConfig.Backend = backend;
        return Task.CompletedTask;
    }

    public Task SaveRagModelAsync(string model)
    {
        SetGlobal(KeyRagModel, model);
        _ollamaConfig.EmbedModel = model;
        return Task.CompletedTask;
    }

    public Task SaveStyleModelAsync(string model)
    {
        SetGlobal(KeyStyleModel, model);
        _ollamaConfig.StyleModel = model;
        return Task.CompletedTask;
    }

    public Task SaveLektorSystemPromptAsync(string prompt)
    {
        Set(KeyLektorPrompt, prompt);
        _ollamaConfig.LektorSystemPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveFactCheckTemplateAsync(string prompt)
    {
        Set(KeyFactCheckTemplate, prompt);
        _ollamaConfig.FactCheckTemplate = prompt;
        return Task.CompletedTask;
    }

    public Task SaveSpellingPromptAsync(string prompt)
    {
        Set(KeySpellingPrompt, prompt);
        _ollamaConfig.SpellingPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveSpellingModelAsync(string model)
    {
        SetGlobal(KeySpellingModel, model);
        _ollamaConfig.SpellingModel = model;
        return Task.CompletedTask;
    }

    public Task SaveAdvocatusDiaboliPromptAsync(string prompt)
    {
        Set(KeyAdvocatusDiaboli, prompt);
        _ollamaConfig.AdvocatusDiaboliPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveHookFinderPromptAsync(string prompt)
    {
        Set(KeyHookFinder, prompt);
        _ollamaConfig.HookFinderPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveEli5PromptAsync(string prompt)
    {
        Set(KeyEli5, prompt);
        _ollamaConfig.Eli5Prompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveCoAuthorBrainstormingPromptAsync(string prompt)
    {
        Set(KeyCoAuthor, prompt);
        _ollamaConfig.CoAuthorBrainstormingPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveLektorTempAsync(double temp)
    {
        Set(KeyLektorTemp, temp.ToString("F1"));
        _ollamaConfig.LektorTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveFactCheckTempAsync(double temp)
    {
        Set(KeyFactCheckTemp, temp.ToString("F1"));
        _ollamaConfig.FactCheckTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveSpellingTempAsync(double temp)
    {
        Set(KeySpellingTemp, temp.ToString("F1"));
        _ollamaConfig.SpellingTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveAdvocatusDiaboliTempAsync(double temp)
    {
        Set(KeyAdvocatusDiaboliTemp, temp.ToString("F1"));
        _ollamaConfig.AdvocatusDiaboliTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveHookFinderTempAsync(double temp)
    {
        Set(KeyHookFinderTemp, temp.ToString("F1"));
        _ollamaConfig.HookFinderTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveEli5TempAsync(double temp)
    {
        Set(KeyEli5Temp, temp.ToString("F1"));
        _ollamaConfig.Eli5Temp = temp;
        return Task.CompletedTask;
    }

    public Task SaveCoAuthorTempAsync(double temp)
    {
        Set(KeyCoAuthorTemp, temp.ToString("F1"));
        _ollamaConfig.CoAuthorTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveTechLastenheftPromptAsync(string prompt)
    {
        Set(KeyTechLastenheft, prompt);
        _ollamaConfig.TechLastenheftPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveTechPflichtenheftPromptAsync(string prompt)
    {
        Set(KeyTechPflichtenheft, prompt);
        _ollamaConfig.TechPflichtenheftPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveTechUseCasePromptAsync(string prompt)
    {
        Set(KeyTechUseCase, prompt);
        _ollamaConfig.TechUseCasePrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveTechStakeholderPromptAsync(string prompt)
    {
        Set(KeyTechStakeholder, prompt);
        _ollamaConfig.TechStakeholderPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveTechGlossarPromptAsync(string prompt)
    {
        Set(KeyTechGlossar, prompt);
        _ollamaConfig.TechGlossarPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveTechQualitaetPromptAsync(string prompt)
    {
        Set(KeyTechQualitaet, prompt);
        _ollamaConfig.TechQualitaetPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveTechRisikoPromptAsync(string prompt)
    {
        Set(KeyTechRisiko, prompt);
        _ollamaConfig.TechRisikoPrompt = prompt;
        return Task.CompletedTask;
    }

    public Task SaveTechLastenheftTempAsync(double temp)
    {
        Set(KeyTechLastenheftTemp, temp.ToString("F1"));
        _ollamaConfig.TechLastenheftTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveTechPflichtenheftTempAsync(double temp)
    {
        Set(KeyTechPflichtenheftTemp, temp.ToString("F1"));
        _ollamaConfig.TechPflichtenheftTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveTechUseCaseTempAsync(double temp)
    {
        Set(KeyTechUseCaseTemp, temp.ToString("F1"));
        _ollamaConfig.TechUseCaseTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveTechStakeholderTempAsync(double temp)
    {
        Set(KeyTechStakeholderTemp, temp.ToString("F1"));
        _ollamaConfig.TechStakeholderTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveTechGlossarTempAsync(double temp)
    {
        Set(KeyTechGlossarTemp, temp.ToString("F1"));
        _ollamaConfig.TechGlossarTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveTechQualitaetTempAsync(double temp)
    {
        Set(KeyTechQualitaetTemp, temp.ToString("F1"));
        _ollamaConfig.TechQualitaetTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveTechRisikoTempAsync(double temp)
    {
        Set(KeyTechRisikoTemp, temp.ToString("F1"));
        _ollamaConfig.TechRisikoTemp = temp;
        return Task.CompletedTask;
    }

    public Task SaveThemeAsync(string theme)
    {
        Set(KeyTheme, theme);
        return Task.CompletedTask;
    }

    public Task<List<UserEntity>> GetUsersAsync()
    {
        var col = _db.GetCollection<UserEntity>("users");
        return Task.FromResult(col.FindAll().ToList());
    }

    public Task<UserEntity> GetCurrentUserAsync()
    {
        var col = _db.GetCollection<UserEntity>("users");
        if (_currentUserId != null)
        {
            var user = col.FindById(_currentUserId.Value);
            if (user != null) return Task.FromResult(user);
        }
        return Task.FromResult(col.FindAll().FirstOrDefault() ?? new UserEntity());
    }

    public void SetCurrentUser(int userId)
    {
        _currentUserId = userId;
    }

    public Task<UserEntity> CreateUserAsync(string name)
    {
        var col = _db.GetCollection<UserEntity>("users");
        var hasUsers = col.FindAll().Any();
        var user = new UserEntity
        {
            Name = name,
            Role = hasUsers ? UserRole.Author : UserRole.Administrator
        };
        col.Insert(user);
        return Task.FromResult(user);
    }

    private void MigrateSchema()
    {
        const string schemaKey = "_schema_version";
        var settings = _db.GetCollection<SettingEntity>("settings");
        var schemaSetting = settings.FindOne(s => s.Key == schemaKey && s.UserId == null && s.ProjectId == null);
        var currentVersion = int.TryParse(schemaSetting?.Value, out var v) ? v : 0;

        if (currentVersion < 1)
        {
            var users = _db.GetCollection<UserEntity>("users");
            var all = users.FindAll().OrderBy(u => u.Id).ToList();
            if (all.Count > 0)
            {
                all[0].Role = UserRole.Administrator;
                foreach (var u in all)
                {
                    u.IsActive = true;
                    users.Update(u);
                }
            }

            var authorExists = all.Any(u => u.Name == "Author");
            if (!authorExists)
            {
                var authorUser = new UserEntity
                {
                    Name = "Author",
                    PasswordHash = TotpHelper.HashPassword("author123"),
                    TwoFactorEnabled = false,
                    TwoFactorSecret = string.Empty,
                    Role = UserRole.Author,
                    IsActive = true
                };
                users.Insert(authorUser);
            }

            var projects = _db.GetCollection<ProjectEntity>("projects");
            var orphaned = projects.Find(p => p.UserId == 0).ToList();
            if (orphaned.Count > 0)
            {
                var admin = users.FindAll().OrderBy(u => u.Id).FirstOrDefault();
                if (admin != null)
                {
                    foreach (var p in orphaned)
                    {
                        p.UserId = admin.Id;
                        projects.Update(p);
                    }
                }
            }

            currentVersion = 1;
        }

        if (currentVersion < 2)
        {
            var llmKeys = new[] { KeyOllamaUrl, KeyRagModel, KeyStyleModel, KeySpellingModel };
            foreach (var key in llmKeys)
            {
                var perUser = settings.Find(s => s.Key == key && s.UserId != null).ToList();
                foreach (var s in perUser)
                    settings.Delete(s.Id);

                if (settings.FindOne(s => s.Key == key && s.UserId == null && s.ProjectId == null) == null)
                {
                    var defaultValue = key switch
                    {
                        var k when k == KeyOllamaUrl => _ollamaConfig.OllamaUrl,
                        var k when k == KeyRagModel => _ollamaConfig.EmbedModel,
                        var k when k == KeyStyleModel => _ollamaConfig.StyleModel,
                        var k when k == KeySpellingModel => _ollamaConfig.SpellingModel,
                        _ => ""
                    };
                    settings.Insert(new SettingEntity { Key = key, Value = defaultValue, UserId = null, ProjectId = null });
                }
            }
            currentVersion = 2;
        }

        if (schemaSetting != null)
        {
            schemaSetting.Value = currentVersion.ToString();
            settings.Update(schemaSetting);
        }
        else
        {
            settings.Insert(new SettingEntity { Key = schemaKey, Value = currentVersion.ToString(), UserId = null, ProjectId = null });
        }
    }

    public Task LoadProjectSettingsAsync()
    {
        var globalKeys = new[] { KeyOllamaUrl, KeyLlamaCppUrl, KeyBackend, KeyRagModel, KeyStyleModel, KeySpellingModel };

        foreach (var key in globalKeys)
        {
            var val = GetGlobal(key);
            if (val == null) continue;
            switch (key)
            {
                case var k when k == KeyOllamaUrl: _ollamaConfig.OllamaUrl = val; break;
                case var k when k == KeyLlamaCppUrl: _ollamaConfig.LlamaCppUrl = val; break;
                case var k when k == KeyBackend: _ollamaConfig.Backend = val; break;
                case var k when k == KeyRagModel: _ollamaConfig.EmbedModel = val; break;
                case var k when k == KeyStyleModel: _ollamaConfig.StyleModel = val; break;
                case var k when k == KeySpellingModel: _ollamaConfig.SpellingModel = val; break;
            }
        }

        var tempMap = new (string Key, Action<double> Setter)[]
        {
            (KeyLektorTemp, val => _ollamaConfig.LektorTemp = val),
            (KeyFactCheckTemp, val => _ollamaConfig.FactCheckTemp = val),
            (KeySpellingTemp, val => _ollamaConfig.SpellingTemp = val),
            (KeyAdvocatusDiaboliTemp, val => _ollamaConfig.AdvocatusDiaboliTemp = val),
            (KeyHookFinderTemp, val => _ollamaConfig.HookFinderTemp = val),
            (KeyEli5Temp, val => _ollamaConfig.Eli5Temp = val),
            (KeyCoAuthorTemp, val => _ollamaConfig.CoAuthorTemp = val),
            (KeyTechLastenheftTemp, val => _ollamaConfig.TechLastenheftTemp = val),
            (KeyTechPflichtenheftTemp, val => _ollamaConfig.TechPflichtenheftTemp = val),
            (KeyTechUseCaseTemp, val => _ollamaConfig.TechUseCaseTemp = val),
            (KeyTechStakeholderTemp, val => _ollamaConfig.TechStakeholderTemp = val),
            (KeyTechGlossarTemp, val => _ollamaConfig.TechGlossarTemp = val),
            (KeyTechQualitaetTemp, val => _ollamaConfig.TechQualitaetTemp = val),
            (KeyTechRisikoTemp, val => _ollamaConfig.TechRisikoTemp = val),
        };

        foreach (var entry in tempMap)
        {
            var val = Get(entry.Key);
            if (val != null && double.TryParse(val, out var d))
                entry.Setter(d);
        }

        var userEntries = new (string Key, Action<string> Setter)[]
        {
            (KeyTheme, val => _ollamaConfig.Theme = val),
            (KeyLektorPrompt, val => _ollamaConfig.LektorSystemPrompt = val),
            (KeyFactCheckTemplate, val => _ollamaConfig.FactCheckTemplate = val),
            (KeySpellingPrompt, val => _ollamaConfig.SpellingPrompt = val),
            (KeyAdvocatusDiaboli, val => _ollamaConfig.AdvocatusDiaboliPrompt = val),
            (KeyHookFinder, val => _ollamaConfig.HookFinderPrompt = val),
            (KeyEli5, val => _ollamaConfig.Eli5Prompt = val),
            (KeyCoAuthor, val => _ollamaConfig.CoAuthorBrainstormingPrompt = val),
            (KeyTechLastenheft, val => _ollamaConfig.TechLastenheftPrompt = val),
            (KeyTechPflichtenheft, val => _ollamaConfig.TechPflichtenheftPrompt = val),
            (KeyTechUseCase, val => _ollamaConfig.TechUseCasePrompt = val),
            (KeyTechStakeholder, val => _ollamaConfig.TechStakeholderPrompt = val),
            (KeyTechGlossar, val => _ollamaConfig.TechGlossarPrompt = val),
            (KeyTechQualitaet, val => _ollamaConfig.TechQualitaetPrompt = val),
            (KeyTechRisiko, val => _ollamaConfig.TechRisikoPrompt = val),
            (KeyLanguage, val => _ollamaConfig.Language = val),
        };

        foreach (var entry in userEntries)
        {
            var val = Get(entry.Key);
            if (val != null) entry.Setter(val);
        }

        return Task.CompletedTask;
    }

    public Task InitializeAsync()
    {
        MigrateSchema();

        var settings = _db.GetCollection<SettingEntity>("settings");

        var globalEntries = new (string Key, string Default)[]
        {
            (KeyOllamaUrl, _ollamaConfig.OllamaUrl),
            (KeyLlamaCppUrl, _ollamaConfig.LlamaCppUrl),
            (KeyBackend, _ollamaConfig.Backend),
            (KeyRagModel, _ollamaConfig.EmbedModel),
            (KeyStyleModel, _ollamaConfig.StyleModel),
            (KeySpellingModel, _ollamaConfig.SpellingModel),
        };

        foreach (var entry in globalEntries)
        {
            var existing = settings.FindOne(s =>
                s.Key == entry.Key && s.UserId == null && s.ProjectId == null);

            if (existing != null)
            {
                var val = existing.Value;
                if (entry.Key == KeyOllamaUrl) _ollamaConfig.OllamaUrl = val;
                else if (entry.Key == KeyLlamaCppUrl) _ollamaConfig.LlamaCppUrl = val;
                else if (entry.Key == KeyBackend) _ollamaConfig.Backend = val;
                else if (entry.Key == KeyRagModel) _ollamaConfig.EmbedModel = val;
                else if (entry.Key == KeyStyleModel) _ollamaConfig.StyleModel = val;
                else if (entry.Key == KeySpellingModel) _ollamaConfig.SpellingModel = val;
            }
            else
            {
                settings.Insert(new SettingEntity
                {
                    Key = entry.Key,
                    Value = entry.Default,
                    UserId = null,
                    ProjectId = null
                });
            }
        }

        if (_currentUserId == null)
        {
            var firstUser = _db.GetCollection<UserEntity>("users").FindAll().FirstOrDefault();
            if (firstUser == null) return Task.CompletedTask;
            _currentUserId = firstUser.Id;
        }

        var lang = _ollamaConfig.Language;

        var userEntries = new (string Key, string Default)[]
        {
            (KeyTheme, _ollamaConfig.Theme),
            (KeyLanguage, lang),
            (KeyLektorPrompt, lang == "en" ? _ollamaConfig.LektorSystemPromptEn : _ollamaConfig.LektorSystemPrompt),
            (KeyFactCheckTemplate, lang == "en" ? _ollamaConfig.FactCheckTemplateEn : _ollamaConfig.FactCheckTemplate),
            (KeySpellingPrompt, lang == "en" ? _ollamaConfig.SpellingPromptEn : _ollamaConfig.SpellingPrompt),
            (KeyAdvocatusDiaboli, lang == "en" ? _ollamaConfig.AdvocatusDiaboliPromptEn : _ollamaConfig.AdvocatusDiaboliPrompt),
            (KeyHookFinder, lang == "en" ? _ollamaConfig.HookFinderPromptEn : _ollamaConfig.HookFinderPrompt),
            (KeyEli5, lang == "en" ? _ollamaConfig.Eli5PromptEn : _ollamaConfig.Eli5Prompt),
            (KeyCoAuthor, lang == "en" ? _ollamaConfig.CoAuthorBrainstormingPromptEn : _ollamaConfig.CoAuthorBrainstormingPrompt),
            (KeyTechLastenheft, lang == "en" ? _ollamaConfig.TechLastenheftPromptEn : _ollamaConfig.TechLastenheftPrompt),
            (KeyTechPflichtenheft, lang == "en" ? _ollamaConfig.TechPflichtenheftPromptEn : _ollamaConfig.TechPflichtenheftPrompt),
            (KeyTechUseCase, lang == "en" ? _ollamaConfig.TechUseCasePromptEn : _ollamaConfig.TechUseCasePrompt),
            (KeyTechStakeholder, lang == "en" ? _ollamaConfig.TechStakeholderPromptEn : _ollamaConfig.TechStakeholderPrompt),
            (KeyTechGlossar, lang == "en" ? _ollamaConfig.TechGlossarPromptEn : _ollamaConfig.TechGlossarPrompt),
            (KeyTechQualitaet, lang == "en" ? _ollamaConfig.TechQualitaetPromptEn : _ollamaConfig.TechQualitaetPrompt),
            (KeyTechRisiko, lang == "en" ? _ollamaConfig.TechRisikoPromptEn : _ollamaConfig.TechRisikoPrompt),
            (KeyLektorTemp, _ollamaConfig.LektorTemp.ToString("F1")),
            (KeyFactCheckTemp, _ollamaConfig.FactCheckTemp.ToString("F1")),
            (KeySpellingTemp, _ollamaConfig.SpellingTemp.ToString("F1")),
            (KeyAdvocatusDiaboliTemp, _ollamaConfig.AdvocatusDiaboliTemp.ToString("F1")),
            (KeyHookFinderTemp, _ollamaConfig.HookFinderTemp.ToString("F1")),
            (KeyEli5Temp, _ollamaConfig.Eli5Temp.ToString("F1")),
            (KeyCoAuthorTemp, _ollamaConfig.CoAuthorTemp.ToString("F1")),
            (KeyTechLastenheftTemp, _ollamaConfig.TechLastenheftTemp.ToString("F1")),
            (KeyTechPflichtenheftTemp, _ollamaConfig.TechPflichtenheftTemp.ToString("F1")),
            (KeyTechUseCaseTemp, _ollamaConfig.TechUseCaseTemp.ToString("F1")),
            (KeyTechStakeholderTemp, _ollamaConfig.TechStakeholderTemp.ToString("F1")),
            (KeyTechGlossarTemp, _ollamaConfig.TechGlossarTemp.ToString("F1")),
            (KeyTechQualitaetTemp, _ollamaConfig.TechQualitaetTemp.ToString("F1")),
            (KeyTechRisikoTemp, _ollamaConfig.TechRisikoTemp.ToString("F1")),
        };

        foreach (var entry in userEntries)
        {
            var existing = settings.FindOne(s =>
                s.Key == entry.Key && s.UserId == _currentUserId && s.ProjectId == _currentProjectId);

            if (existing != null)
            {
                var val = existing.Value;
                if (entry.Key == KeyTheme) _ollamaConfig.Theme = val;
                else if (entry.Key == KeyLanguage) _ollamaConfig.Language = val;
                else if (entry.Key == KeyLektorPrompt) _ollamaConfig.LektorSystemPrompt = val;
                else if (entry.Key == KeyFactCheckTemplate) _ollamaConfig.FactCheckTemplate = val;
                else if (entry.Key == KeySpellingPrompt) _ollamaConfig.SpellingPrompt = val;
                else if (entry.Key == KeyAdvocatusDiaboli) _ollamaConfig.AdvocatusDiaboliPrompt = val;
                else if (entry.Key == KeyHookFinder) _ollamaConfig.HookFinderPrompt = val;
                else if (entry.Key == KeyEli5) _ollamaConfig.Eli5Prompt = val;
                else if (entry.Key == KeyCoAuthor) _ollamaConfig.CoAuthorBrainstormingPrompt = val;
                else if (entry.Key == KeyLektorTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.LektorTemp = t; }
                else if (entry.Key == KeyFactCheckTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.FactCheckTemp = t; }
                else if (entry.Key == KeySpellingTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.SpellingTemp = t; }
                else if (entry.Key == KeyAdvocatusDiaboliTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.AdvocatusDiaboliTemp = t; }
                else if (entry.Key == KeyHookFinderTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.HookFinderTemp = t; }
                else if (entry.Key == KeyEli5Temp) { if (double.TryParse(val, out var t)) _ollamaConfig.Eli5Temp = t; }
                else if (entry.Key == KeyCoAuthorTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.CoAuthorTemp = t; }
                else if (entry.Key == KeyTechLastenheft) _ollamaConfig.TechLastenheftPrompt = val;
                else if (entry.Key == KeyTechPflichtenheft) _ollamaConfig.TechPflichtenheftPrompt = val;
                else if (entry.Key == KeyTechUseCase) _ollamaConfig.TechUseCasePrompt = val;
                else if (entry.Key == KeyTechStakeholder) _ollamaConfig.TechStakeholderPrompt = val;
                else if (entry.Key == KeyTechGlossar) _ollamaConfig.TechGlossarPrompt = val;
                else if (entry.Key == KeyTechQualitaet) _ollamaConfig.TechQualitaetPrompt = val;
                else if (entry.Key == KeyTechRisiko) _ollamaConfig.TechRisikoPrompt = val;
                else if (entry.Key == KeyTechLastenheftTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechLastenheftTemp = t; }
                else if (entry.Key == KeyTechPflichtenheftTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechPflichtenheftTemp = t; }
                else if (entry.Key == KeyTechUseCaseTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechUseCaseTemp = t; }
                else if (entry.Key == KeyTechStakeholderTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechStakeholderTemp = t; }
                else if (entry.Key == KeyTechGlossarTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechGlossarTemp = t; }
                else if (entry.Key == KeyTechQualitaetTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechQualitaetTemp = t; }
                else if (entry.Key == KeyTechRisikoTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechRisikoTemp = t; }
            }
            else
            {
                settings.Insert(new SettingEntity
                {
                    Key = entry.Key,
                    Value = entry.Default,
                    UserId = _currentUserId,
                    ProjectId = _currentProjectId
                });
            }
        }

        return Task.CompletedTask;
    }
}
