using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using FluentResults;
using NexusReader.Application.Abstractions.Messaging;
using NexusReader.Application.Abstractions.Persistence;
using NexusReader.Application.Queries.Graph;
using NexusReader.Application.Utilities;

namespace NexusReader.Application.Queries.Concepts;

internal sealed class GetBookConceptsMapQueryHandler : IQueryHandler<GetBookConceptsMapQuery, BookConceptsMapResultDto>
{
    private readonly IConceptsMapReadRepository _repository;

    public GetBookConceptsMapQueryHandler(IConceptsMapReadRepository repository)
    {
        _repository = repository;
    }

    public async Task<Result<BookConceptsMapResultDto>> Handle(GetBookConceptsMapQuery request, CancellationToken cancellationToken)
    {
        // 1. Fetch user to extract reading progress (LastReadPageId)
        var lastReadPageId = await _repository.GetLastReadPageIdAsync(request.UserId, cancellationToken);
        var lastReadBlockId = lastReadPageId ?? string.Empty;

        // 2. Fetch all KnowledgeUnits associated with the ebook and user's tenant
        var units = await _repository.GetKnowledgeUnitsForBookAsync(request.BookId, request.TenantId, cancellationToken);

        var nodes = new List<GraphNodeDto>();

        foreach (var unit in units)
        {
            // Only process units representing sections or conceptual milestones (usually starting with "seg-")
            if (string.IsNullOrEmpty(unit.Id) || !unit.Id.StartsWith("seg-"))
            {
                continue;
            }

            string label = unit.Id;
            string group = "concept";
            string summary = unit.Content;
            var keyTerms = new List<string>();

            if (!string.IsNullOrEmpty(unit.MetadataJson))
            {
                try
                {
                    using var doc = JsonDocument.Parse(unit.MetadataJson);
                    if (doc.RootElement.TryGetProperty("label", out var labelProp))
                        label = labelProp.GetString() ?? label;
                    if (doc.RootElement.TryGetProperty("group", out var groupProp))
                        group = groupProp.GetString() ?? group;
                    if (doc.RootElement.TryGetProperty("summary", out var summaryProp))
                        summary = summaryProp.GetString() ?? summary;
                    if (doc.RootElement.TryGetProperty("key_terms", out var ktProp) && ktProp.ValueKind == JsonValueKind.Array)
                    {
                        foreach (var term in ktProp.EnumerateArray())
                        {
                            if (term.GetString() is string s)
                                keyTerms.Add(s);
                        }
                    }
                }
                catch
                {
                    // Fallback to defaults
                }
            }

            nodes.Add(new GraphNodeDto(
                Id: unit.Id,
                Label: label,
                Group: group,
                Description: unit.Content,
                Type: unit.Type.ToString(),
                Summary: summary,
                KeyTerms: keyTerms
            ));
        }

        // Return sorted by the numeric value in the seg-ID to ensure topdown vertical alignment
        var sortedNodes = nodes
            .OrderBy(n => SegmentIdParser.Parse(n.Id))
            .ToList();

        return Result.Ok(new BookConceptsMapResultDto(sortedNodes, lastReadBlockId));
    }
}
