using System.Text.Json.Nodes;
using GerbilManagerWebAPI.Models;
using Microsoft.EntityFrameworkCore;

namespace GerbilManagerWebAPI.Cms
{
    /// <summary>
    /// Builds the full CMS snapshot consumed by the static site renderer (WEB-1). The
    /// abgabetiere page's auto AbgabetiereList block is resolved here from live ForSale
    /// animals — nothing private is ever exposed (publish = snapshot of public content).
    /// </summary>
    public sealed class SiteSnapshotService
    {
        private readonly ApplicationContext _db;

        public SiteSnapshotService(ApplicationContext db) => _db = db;

        public async Task<JsonObject> BuildAsync()
        {
            var site = await _db.Sites.AsNoTracking().FirstOrDefaultAsync()
                       ?? new Site { Id = Site.SingletonId };
            var pages = await _db.Pages.AsNoTracking().Include(p => p.Blocks).ToListAsync();
            var pageById = pages.ToDictionary(p => p.Id);

            var navOrder = new JsonArray();
            foreach (var id in site.NavOrder)
                if (pageById.TryGetValue(id, out var p))
                    navOrder.Add(p.Slug);

            JsonArray? forSale = null;   // resolved lazily, reused across blocks

            int NavIndex(Guid id) { var i = site.NavOrder.IndexOf(id); return i < 0 ? int.MaxValue : i; }

            var pagesArr = new JsonArray();
            foreach (var page in pages.OrderBy(p => NavIndex(p.Id)).ThenBy(p => p.Slug))
            {
                var blocks = new JsonArray();
                foreach (var b in page.Blocks.OrderBy(b => b.Order))
                {
                    var data = JsonNode.Parse(string.IsNullOrWhiteSpace(b.Data) ? "{}" : b.Data) as JsonObject
                               ?? new JsonObject();
                    if (b.Type == BlockType.AbgabetiereList && AsString(data["mode"]) == "auto")
                    {
                        forSale ??= await BuildForSaleAsync();
                        data["animals"] = forSale.DeepClone();
                    }
                    blocks.Add(new JsonObject
                    {
                        ["id"] = b.Id.ToString(),
                        ["order"] = b.Order,
                        ["type"] = b.Type.ToString(),
                        ["data"] = data,
                    });
                }
                pagesArr.Add(new JsonObject
                {
                    ["slug"] = page.Slug,
                    ["title"] = page.Title,
                    ["seoDescription"] = page.SeoDescription,
                    ["status"] = page.Status.ToString(),
                    ["blocks"] = blocks,
                });
            }

            return new JsonObject
            {
                ["site"] = new JsonObject
                {
                    ["defaultLocale"] = site.DefaultLocale,
                    ["navOrder"] = navOrder,
                },
                ["pages"] = pagesArr,
            };
        }

        private async Task<JsonArray> BuildForSaleAsync()
        {
            var animals = await _db.Gerbils.AsNoTracking()
                .Where(g => g.Status == GerbilStatus.ForSale)
                .OrderBy(g => g.Name)
                .Select(g => new
                {
                    g.Id,
                    g.Name,
                    g.Gender,
                    g.DateOfBirth,
                    g.CharacterNote,
                    Farbschlag = g.ColorVariety != null ? g.ColorVariety.Name : null,
                    // group = Becken (enclosure) name — matches how the Abgabe composer
                    // groups ForSale animals by enclosure-mates (god ruling). null = single.
                    Group = g.Enclosure != null ? g.Enclosure.Name : null,
                })
                .ToListAsync();

            var ids = animals.Select(a => a.Id).ToList();
            var photos = await _db.GerbilPhotos.AsNoTracking()
                .Where(p => ids.Contains(p.GerbilId))
                .OrderBy(p => p.SortOrder)
                .Select(p => new { p.GerbilId, p.FileName })
                .ToListAsync();
            var photosByGerbil = photos
                .GroupBy(p => p.GerbilId)
                .ToDictionary(g => g.Key, g => g.Select(x => $"/photos/files/{x.FileName}").ToList());

            var arr = new JsonArray();
            foreach (var a in animals)
            {
                var photoArr = new JsonArray();
                if (photosByGerbil.TryGetValue(a.Id, out var urls))
                    foreach (var u in urls) photoArr.Add(u);

                arr.Add(new JsonObject
                {
                    ["name"] = a.Name,
                    ["gender"] = a.Gender.ToString(),
                    ["dateOfBirth"] = a.DateOfBirth?.ToString("yyyy-MM-dd"),
                    ["characterNote"] = a.CharacterNote,
                    ["farbschlag"] = a.Farbschlag,
                    ["group"] = a.Group,
                    ["photos"] = photoArr,
                    ["aiSaleText"] = null,   // populated by WEB-5 once a Gemini key exists
                });
            }
            return arr;
        }

        private static string? AsString(JsonNode? node) =>
            node is JsonValue v && v.TryGetValue<string>(out var s) ? s : null;
    }
}
