using PlotLine.Data;
using PlotLine.Models;

namespace PlotLine.Services;

public interface IStoryIntelligenceExistingChapterQueueService
{
    Task<StoryIntelligenceExistingChapterQueueViewModel> BuildViewModelAsync(StoryIntelligenceExistingChapterQueueForm form);
    Task<StoryIntelligenceExistingChapterQueueViewModel> QueueAsync(int userId, StoryIntelligenceExistingChapterQueueForm form);
}

public sealed class StoryIntelligenceExistingChapterQueueService(
    IStoryIntelligenceSourceRepository sources,
    IStoryIntelligenceResultRepository runs,
    IStoryIntelligenceClient client,
    IStoryIntelligencePipelineStateService pipelines,
    ILogger<StoryIntelligenceExistingChapterQueueService> logger) : IStoryIntelligenceExistingChapterQueueService
{
    private const string NoStoredChapterTextMessage = "No stored chapter text is currently available for this chapter. A future Word Companion/document extraction phase is required.";

    public async Task<StoryIntelligenceExistingChapterQueueViewModel> BuildViewModelAsync(StoryIntelligenceExistingChapterQueueForm form)
    {
        var selected = await GetSelectedChapterAsync(form);
        return await BuildViewModelAsync(form, selected, warningMessage: BuildWarning(selected), errorMessage: null, queuedRunId: null);
    }

    public async Task<StoryIntelligenceExistingChapterQueueViewModel> QueueAsync(int userId, StoryIntelligenceExistingChapterQueueForm form)
    {
        if (form.ChapterID is not int chapterId)
        {
            return await BuildViewModelAsync(
                form,
                selectedChapter: null,
                warningMessage: null,
                errorMessage: "Choose a chapter before queueing a Story Intelligence run.",
                queuedRunId: null);
        }

        var selected = await sources.GetChapterSourceAsync(chapterId);
        if (selected is null)
        {
            return await BuildViewModelAsync(
                form,
                selectedChapter: null,
                warningMessage: null,
                errorMessage: "The selected chapter could not be found.",
                queuedRunId: null);
        }

        if (!selected.HasSourceText)
        {
            return await BuildViewModelAsync(
                NormalizeForm(selected),
                selected,
                NoStoredChapterTextMessage,
                errorMessage: null,
                queuedRunId: null);
        }

        var sourceText = selected.SourceText!.Trim();
        var clientStatus = client.GetConfigurationStatus();
        var runId = await runs.QueueAdminTextAsync(new StoryIntelligenceRunQueueRequest
        {
            UserID = userId,
            ProjectID = selected.ProjectID,
            BookID = selected.BookID,
            ChapterID = selected.ChapterID,
            ChapterNumber = selected.ChapterNumber,
            SourceType = "ExistingChapter",
            SourceLabel = BuildSourceLabel(selected),
            ChapterText = sourceText,
            SourceWordCount = selected.SourceWordCount ?? CountWords(sourceText),
            SourceCharacterCount = selected.SourceCharacterCount ?? sourceText.Length,
            SourceParagraphCount = StoryIntelligenceParagraphs.Split(sourceText).Count,
            SourceChapterCount = 1,
            Model = StoryIntelligenceOptions.BuildModelSummary(
                clientStatus.ChapterStructureModel,
                clientStatus.SceneIntelligenceModel),
            PromptVersionsSummary = "Chapter=Chapter-Structure-Prompt-V2; Scene=Scene-Prompt-V2"
        });
        await pipelines.RecordChapterAnalysisQueuedAsync(selected.ProjectID, selected.BookID, runId);

        logger.LogInformation(
            "Queued Story Intelligence run {StoryIntelligenceRunID} from existing chapter {ChapterID}. ProjectID={ProjectID} BookID={BookID} SourceWordCount={SourceWordCount} SourceCharacterCount={SourceCharacterCount}",
            runId,
            selected.ChapterID,
            selected.ProjectID,
            selected.BookID,
            selected.SourceWordCount,
            selected.SourceCharacterCount);

        return await BuildViewModelAsync(NormalizeForm(selected), selected, warningMessage: null, errorMessage: null, queuedRunId: runId);
    }

    private async Task<StoryIntelligenceExistingChapterQueueViewModel> BuildViewModelAsync(
        StoryIntelligenceExistingChapterQueueForm form,
        StoryIntelligenceExistingChapterSource? selectedChapter,
        string? warningMessage,
        string? errorMessage,
        int? queuedRunId)
    {
        var normalizedForm = selectedChapter is not null ? NormalizeForm(selectedChapter) : form;
        var projects = await sources.ListProjectsAsync();
        var books = normalizedForm.ProjectID is int projectId
            ? await sources.ListBooksAsync(projectId)
            : [];
        var chapters = normalizedForm.BookID is int bookId
            ? await sources.ListChaptersAsync(bookId)
            : [];

        return new StoryIntelligenceExistingChapterQueueViewModel
        {
            Form = normalizedForm,
            Projects = projects,
            Books = books,
            Chapters = chapters,
            SelectedChapter = selectedChapter,
            WarningMessage = warningMessage,
            ErrorMessage = errorMessage,
            QueuedRunID = queuedRunId
        };
    }

    private async Task<StoryIntelligenceExistingChapterSource?> GetSelectedChapterAsync(StoryIntelligenceExistingChapterQueueForm form)
        => form.ChapterID is int chapterId ? await sources.GetChapterSourceAsync(chapterId) : null;

    private static string? BuildWarning(StoryIntelligenceExistingChapterSource? selected)
        => selected is not null && !selected.HasSourceText ? NoStoredChapterTextMessage : null;

    private static StoryIntelligenceExistingChapterQueueForm NormalizeForm(StoryIntelligenceExistingChapterSource selected)
        => new()
        {
            ProjectID = selected.ProjectID,
            BookID = selected.BookID,
            ChapterID = selected.ChapterID
        };

    private static string BuildSourceLabel(StoryIntelligenceExistingChapterSource selected)
    {
        var book = string.IsNullOrWhiteSpace(selected.BookSubtitle)
            ? selected.BookTitle
            : $"{selected.BookTitle}: {selected.BookSubtitle}";
        return $"{selected.ProjectName} / {book} / Chapter {selected.ChapterNumber}: {selected.ChapterTitle}";
    }

    private static int? CountWords(string? value)
        => string.IsNullOrWhiteSpace(value)
            ? null
            : value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries).Length;
}
