@page "/assistant"
@attribute [Authorize]
@inject IOllamaService OllamaService
@inject ISettingsService SettingsService
@inject IRagService RagService
@inject IProjectService ProjectService
@inject NavigationManager Navigation
@inject ILocalizationService Loc
@inject OperationState OpState

<PageTitle>@Loc["page.title.assistant"]</PageTitle>

<div class="assistant-page">
    <div class="assistant-toolbar">
        <select value="@selectedMode" @onchange="OnModeChanged">
            <option value="lektorat">@Loc["assistant.mode.lektorat"]</option>
            <option value="advocatus">@Loc["assistant.mode.advocatus"]</option>
            <option value="hookfinder">@Loc["assistant.mode.hookfinder"]</option>
            <option value="eli5">@Loc["assistant.mode.eli5"]</option>
            <option value="coauthor">@Loc["assistant.mode.coauthor"]</option>
            <option value="rag">@Loc["assistant.mode.rag"]</option>
            @if (currentTemplate == ProjectTemplate.Technical)
            {
                <option disabled style="font-style:italic;">── Requirements ──</option>
                <option value="tech_lastenheft">@Loc["assistant.mode.tech_lastenheft"]</option>
                <option value="tech_pflichtenheft">@Loc["assistant.mode.tech_pflichtenheft"]</option>
                <option value="tech_usecase">@Loc["assistant.mode.tech_usecase"]</option>
                <option value="tech_stakeholder">@Loc["assistant.mode.tech_stakeholder"]</option>
                <option value="tech_glossar">@Loc["assistant.mode.tech_glossar"]</option>
                <option value="tech_qualitaet">@Loc["assistant.mode.tech_qualitaet"]</option>
                <option value="tech_risiko">@Loc["assistant.mode.tech_risiko"]</option>
            }
        </select>
        <button @onclick="RunAssistant" disabled="@(() => isRunning || string.IsNullOrWhiteSpace(inputText))">@Loc["assistant.button.execute"]</button>
        @if (!string.IsNullOrEmpty(outputText))
        {
            <button @onclick="SendToEditor" class="primary">@Loc["assistant.button.send_to_editor"]</button>
        }
        <button @onclick='() => showPromptEditor = !showPromptEditor' class="btn-small">
            @(showPromptEditor ? Loc["assistant.button.hide_prompt"] : Loc["assistant.button.edit_prompt"])
        </button>
        <span style="flex:1;font-size:12px;color:var(--border-color);text-align:right;">@statusText</span>
        @if (isRunning)
        {
            <progress value="@progress" max="100"></progress>
        }
    </div>

    @if (showPromptEditor && selectedMode != "rag")
    {
        <div class="assistant-prompt-editor">
            <div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">
                <strong style="font-size:13px;">@Loc["assistant.label.system_prompt"]</strong>
                <button class="btn-small" @onclick="ResetPrompt">@Loc["assistant.button.reset_prompt"]</button>
            </div>
            <textarea class="assistant-prompt-textarea" @bind="promptOverride" rows="4"></textarea>
            <div class="temp-slider" style="margin-top:6px;">
                <label class="temp-label">@Loc["settings.temperature.label"] <span class="temp-value">@temperatureOverride.ToString("F1")</span></label>
                <input type="range" min="0" max="2" step="0.1" value="@Fmt(temperatureOverride)" @oninput="OnTempChanged" />
            </div>
        </div>
    }

    <div class="assistant-panels">
        <div class="assistant-input-panel">
            <h4 style="display:inline">@Loc["assistant.label.input_text"]</h4>
            <CopyCreateToolbar Text="@inputText" DefaultFileName="assistent_eingabe" />
            <textarea class="assistant-textarea" @bind="inputText" placeholder="@Loc["assistant.placeholder.input"]"></textarea>
        </div>
        <div class="assistant-output-panel">
            <h4 style="display:inline">@Loc["assistant.label.result"]</h4>
            <CopyCreateToolbar Text="@outputText" DefaultFileName="assistent_ausgabe" />
            <div class="assistant-output">
                @if (!string.IsNullOrEmpty(outputText))
                {
                    <pre>@outputText</pre>
                }
                else if (!string.IsNullOrEmpty(errorMessage))
                {
                    <div class="assistant-error">@errorMessage</div>
                }
                else
                {
                    <span class="assistant-hint">@Loc["assistant.hint.empty_result"]</span>
                }
            </div>
        </div>
    </div>
</div>

@code {
    private string selectedMode = "lektorat";
    private string inputText = string.Empty;
    private string outputText = string.Empty;
    private string errorMessage = string.Empty;
    private string statusText = string.Empty;
    private bool isRunning;
    private double progress;
    private bool showPromptEditor;
    private string promptOverride = string.Empty;
    private double temperatureOverride = 0.7;
    private ProjectTemplate currentTemplate = ProjectTemplate.Novel;

    protected override async Task OnInitializedAsync()
    {
        statusText = Loc["common.status.ready"];
        await LoadPromptForMode();

        var pid = SettingsService.CurrentProjectId;
        if (pid != null)
        {
            var project = await ProjectService.GetProjectAsync(pid.Value);
            if (project != null)
                currentTemplate = project.Template;
        }

        var pending = SettingsService.PendingAssistantInput;
        if (!string.IsNullOrEmpty(pending))
        {
            inputText = pending;
            SettingsService.PendingAssistantInput = null;
        }
    }

    private async Task OnModeChanged(ChangeEventArgs e)
    {
        selectedMode = e.Value?.ToString() ?? "lektorat";
        await LoadPromptForMode();
    }

    private async Task LoadPromptForMode()
    {
        if (selectedMode == "rag")
        {
            promptOverride = string.Empty;
            temperatureOverride = 0.3;
            return;
        }

        var (prompt, temp) = selectedMode switch
        {
            "lektorat" => (await SettingsService.GetLektorSystemPromptAsync() ?? string.Empty, await SettingsService.GetLektorTempAsync()),
            "advocatus" => (await SettingsService.GetAdvocatusDiaboliPromptAsync() ?? string.Empty, await SettingsService.GetAdvocatusDiaboliTempAsync()),
            "hookfinder" => (await SettingsService.GetHookFinderPromptAsync() ?? string.Empty, await SettingsService.GetHookFinderTempAsync()),
            "eli5" => (await SettingsService.GetEli5PromptAsync() ?? string.Empty, await SettingsService.GetEli5TempAsync()),
            "coauthor" => (await SettingsService.GetCoAuthorBrainstormingPromptAsync() ?? string.Empty, await SettingsService.GetCoAuthorTempAsync()),
            "tech_lastenheft" => (await SettingsService.GetTechLastenheftPromptAsync() ?? string.Empty, await SettingsService.GetTechLastenheftTempAsync()),
            "tech_pflichtenheft" => (await SettingsService.GetTechPflichtenheftPromptAsync() ?? string.Empty, await SettingsService.GetTechPflichtenheftTempAsync()),
            "tech_usecase" => (await SettingsService.GetTechUseCasePromptAsync() ?? string.Empty, await SettingsService.GetTechUseCaseTempAsync()),
            "tech_stakeholder" => (await SettingsService.GetTechStakeholderPromptAsync() ?? string.Empty, await SettingsService.GetTechStakeholderTempAsync()),
            "tech_glossar" => (await SettingsService.GetTechGlossarPromptAsync() ?? string.Empty, await SettingsService.GetTechGlossarTempAsync()),
            "tech_qualitaet" => (await SettingsService.GetTechQualitaetPromptAsync() ?? string.Empty, await SettingsService.GetTechQualitaetTempAsync()),
            "tech_risiko" => (await SettingsService.GetTechRisikoPromptAsync() ?? string.Empty, await SettingsService.GetTechRisikoTempAsync()),
            _ => (string.Empty, 0.0)
        };

        promptOverride = prompt;
        temperatureOverride = temp;
    }

    private async Task ResetPrompt()
    {
        await LoadPromptForMode();
    }

    private void OnTempChanged(ChangeEventArgs e)
    {
        if (e.Value is string s && double.TryParse(s, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var v))
            temperatureOverride = Math.Round(v, 1);
    }

    private string Fmt(double v) => v.ToString("F1", System.Globalization.CultureInfo.InvariantCulture);

    private async Task RunAssistant()
    {
        if (string.IsNullOrWhiteSpace(inputText)) return;

        isRunning = true;
        progress = 50;
        outputText = string.Empty;
        errorMessage = string.Empty;
        statusText = Loc["assistant.status.starting"];
        OpState.SetStatus(Loc["assistant.status.starting"], true);
        OpState.SetThought("");

        try
        {
            if (selectedMode == "rag")
            {
                var projectId = SettingsService.CurrentProjectId;
                if (projectId == null)
                {
                    errorMessage = Loc["assistant.error.no_project"];
                    return;
                }

                OpState.SetStatus(Loc["assistant.status.searching"], true);
                progress = 30;
                var results = await RagService.SearchAsync(projectId.Value, inputText, 5);
                if (results.Count == 0)
                {
                    errorMessage = Loc["assistant.error.no_facts"];
                    return;
                }

                var facts = string.Join("\n\n---\n\n", results.Select(r => r.Text));
                progress = 70;
                OpState.SetStatus(Loc["assistant.status.processing"], true);
                outputText = await OllamaService.AnswerBasedOnFactsAsync(inputText, facts);
                OpState.SetThought(outputText);
                statusText = Loc["assistant.status.done"];
                OpState.SetStatus(Loc["assistant.status.done"], false);
            }
            else
            {
                var systemPrompt = promptOverride;

                if (string.IsNullOrEmpty(systemPrompt))
                {
                    errorMessage = Loc["assistant.error.no_prompt"];
                    return;
                }

                if (selectedMode is "coauthor" or "hookfinder" or "lektorat")
                {
                    var projectId = SettingsService.CurrentProjectId;
                    if (projectId != null)
                    {
                        var project = await ProjectService.GetProjectAsync(projectId.Value);
                        if (project != null)
                        {
                            // Use Exposé file from category system
                            var categories = await ProjectService.GetFileCategoriesAsync(projectId.Value);
                            var exposeFile = categories.FirstOrDefault(c => c.Value == FileCategory.Exposee);
                            if (!string.IsNullOrEmpty(exposeFile.Key) && File.Exists(exposeFile.Key))
                            {
                                var exposee = await File.ReadAllTextAsync(exposeFile.Key);
                                if (!string.IsNullOrWhiteSpace(exposee))
                                {
                                    systemPrompt += "\n\n" + Loc["assistant.exposee.context"] + "\n" + exposee;
                                }
                            }
                        }
                    }
                }

                var model = await SettingsService.GetStyleModelAsync() ?? "llama3.2";
                OpState.SetStatus(Loc["assistant.status.processing"], true);
                statusText = Loc["assistant.status.processing"];

                await OllamaService.ChatStream(model, inputText, async chunk =>
                {
                    outputText += chunk;
                    OpState.AppendThought(chunk);
                    await InvokeAsync(StateHasChanged);
                }, systemPrompt, temperatureOverride);

                statusText = Loc["assistant.status.done"];
                OpState.SetStatus(Loc["assistant.status.done"], false);
            }
        }
        catch (Exception ex)
        {
            errorMessage = $"{Loc["common.error"]} {ex.Message}";
            statusText = Loc["common.status.error"];
            OpState.SetStatus($"{Loc["common.error"]} {ex.Message}", false);
        }
        finally
        {
            isRunning = false;
            progress = 0;
        }
    }

    private void SendToEditor()
    {
        SettingsService.PendingAssistantOutput = outputText;
        Navigation.NavigateTo("/editor");
    }
}
