
using Mapster;
using QYZH.InteractiveMagazine.Common.Extensions;
using QYZH.InteractiveMagazine.Infrastructure.OSS;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Base;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.Journal;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Repository;
using SqlSugar;
using Yitter.IdGenerator;

namespace QYZH.InteractiveMagazine.Service;

public class JournalCatalogService : BaseRepository<JournalCatalog>, IJournalCatalogService
{
    private readonly BaseRepository<JournalPage> _JournalPageRepository;
    private readonly BaseRepository<JournalPageTask> _JournalPageTaskRepository;
    private readonly OssService _ossService;

    public JournalCatalogService(BaseRepository<JournalPage> JournalPageRepository, BaseRepository<JournalPageTask> JournalPageTaskRepository, OssService ossService)
    {
        //_JournalRepository = JournalRepository;
        _JournalPageRepository = JournalPageRepository;
        _ossService = ossService;
    }

    public async Task<List<JournalCatalog>> DetailAsync(long JournalId)
    {
        return await base.Queryable().Where(w => w.ParentId == 0 && w.JournalId == JournalId).OrderBy(o => o.Sort).ToChildListAsync(it => it.ParentId, 0) ?? [];
    }

    public async Task<long> ImportAsync(JournalImportDto input)
    {
        var Journals = await Queryable<Journal>().Where(w => w.Id == input.JournalId).FirstAsync();
        BusinessException.ThrowIf(Journals.IsNull(), "未找到书本", ResultCode.NOT_FOUND);

        var pageNum = await _JournalPageRepository.Queryable().Where(w => w.JournalId == input.JournalId).MaxAsync(m => m.PageNum);
        BusinessException.ThrowIf(pageNum != 0, "已经存在书页", ResultCode.CONFLICT);


        var JournalCatalog = new JournalCatalog()
        {
            Id = YitIdHelper.NextId(),
            JournalId = input.JournalId,
            Name = "目录",
            ParentId = 0,
            Level = 0,
            Sort = 1,
            Type = JournalCatalogTypeEnum.Page,
        };

        int sort = 1;
        var result = input.JournalCatalogs.Where(w => w.Type == 1).Select(s =>
        {
            var JournalPage = new JournalPage
            {
                Id = YitIdHelper.NextId(),
                JournalId = input.JournalId,
                JournalCatalogId = JournalCatalog.Id,
                Sort = sort,
                PageNum = sort < input.Index ? 0 : sort - (input.Index - 1)
            };
            var key = $"journal/{input.JournalId}/{JournalPage.Id}/page.{s.Url.ToExtension()}";
            _ossService.CopyObject(s.Url.RemoveDomain(), key);

            JournalPage.Url = key;
            //dotMatrixPage.PreviewUrl = key;

            sort = sort + 1;
            return new
            {
                JournalPage = JournalPage
            };
        }).ToList();

        await UseTranAsync(async () =>
        {
           
            var data = await base.InsertAsync(JournalCatalog);

            var JournalPages = result.Select(x => x.JournalPage).ToList();
            await _JournalPageRepository.InsertRangeAsync(JournalPages);

            var key = $"journal/{input.JournalId}/Journal.pdf";
            _ossService.CopyObject(input.PdfUrl.RemoveDomain(), key);

            await Updateable<Journal>().SetColumns(s => s.PdfUrl, key)
                        .SetColumns(s => s.Status, JournalStatusEnum.Created)
                        .SetColumns(s => s.TotalPage, JournalPages.Count).Where(w => w.Id == input.JournalId)
                        .ExecuteCommandAsync();
        });

        return result.Count;
    }



    /// <summary>
    /// 获取书分类及页码
    /// </summary>
    /// <param name="JournalId"></param>
    /// <returns></returns>
    public async Task<List<JournalCatalogTreeListDto>> GetJournalCatalogListAsync(long JournalId)
    {
        var Journal = await Queryable<Journal>().Where(w => w.Id == JournalId).FirstAsync();
        BusinessException.ThrowIf(Journal.IsNull(), "未找到书本", ResultCode.NOT_FOUND);

        var pageNumList = await _JournalPageRepository.Queryable()
            .InnerJoin<JournalCatalog>((a, b) => a.JournalCatalogId == b.Id)
            .Where((a, b) => a.JournalId == JournalId)
            .OrderBy((a, b) => a.PageNum)
            .Select((a, b) => new JournalCatalogTreeListDto
            {
                JournalId = a.JournalId,
                Id = b.Id,
                Name = b.Name,
                PageNum = a.PageNum,
                ParentName = SqlFunc.Subqueryable<JournalCatalog>().Where(c => c.Id == b.ParentId).Select(c => c.Name),
                ParentId = b.ParentId,
                PageId = a.Id,
            })
            .ToListAsync();

        return pageNumList;
    }


    /// <summary>
    /// 获取书分类及页码
    /// </summary>
    /// <param name="JournalId"></param>
    /// <returns></returns>
    public async Task<List<IcrJournalCatalogTreeDto>> GetJournalCataloTreeAsync(long JournalId)
    {
        var Journal = await Queryable<Journal>().Where(w => w.Id == JournalId).FirstAsync();
        BusinessException.ThrowIf(Journal.IsNull(), "未找到书本", ResultCode.NOT_FOUND);

        // 先查询所有目录
        var allCatalogs = await base.Queryable()
            .Where(w => w.JournalId == JournalId)
            .OrderBy(o => o.Sort)
            .ToListAsync();

        if (!allCatalogs.Any())
            return new List<IcrJournalCatalogTreeDto>();

        // 再查询有页面对应的目录及页面信息
        var pageNumList = await _JournalPageRepository.Queryable()
            .InnerJoin<JournalCatalog>((a, b) => a.JournalCatalogId == b.Id)
            .Where((a, b) => a.JournalId == JournalId)
            .OrderBy((a, b) => a.PageNum)
            .Select((a, b) => new JournalCatalogTreeListDto
            {
                JournalId = a.JournalId,
                Id = b.Id,
                Name = b.Name,
                PageNum = a.PageNum,
                ParentName = SqlFunc.Subqueryable<JournalCatalog>().Where(c => c.Id == b.ParentId).Select(c => c.Name),
                ParentId = b.ParentId,
                PageId = a.Id,
            })
            .ToListAsync();

        var tree = BuildCatalogTree(allCatalogs, pageNumList);

        return tree;
    }

    /// <summary>
    /// 构建目录树形结构（支持任意层级）
    /// </summary>
    /// <param name="allCatalogs">所有目录</param>
    /// <param name="pageNumList">有页面对应的目录信息</param>
    /// <returns></returns>
    private List<IcrJournalCatalogTreeDto> BuildCatalogTree(List<JournalCatalog> allCatalogs, List<JournalCatalogTreeListDto> pageNumList)
    {
        // 构建有页面对应的目录到页面列表的映射
        var catalogPagesMap = pageNumList
            .GroupBy(x => x.Id)
            .ToDictionary(
                g => g.Key,
                g => g.Select(p => new IcrJournalCatalogTreeDto
                {
                    Id = p.PageId,
                    Name = $"第{p.PageNum}页",
                    Level = 0,
                    Child = new List<IcrJournalCatalogTreeDto>()
                }).ToList()
            );

        // 构建所有目录节点字典
        var catalogDict = new Dictionary<long, IcrJournalCatalogTreeDto>();
        var rootCatalogIds = new HashSet<long>();

        foreach (var catalog in allCatalogs)
        {
            var catalogId = catalog.Id;
            var parentId = catalog.ParentId;

            if (catalogDict.ContainsKey(catalogId))
                continue;

            var node = new IcrJournalCatalogTreeDto
            {
                Id = catalogId,
                Name = catalog.Name,
                Level = 0,
                Child = catalogPagesMap.GetValueOrDefault(catalogId, new List<IcrJournalCatalogTreeDto>())
            };

            catalogDict[catalogId] = node;

            if (parentId == 0)
            {
                rootCatalogIds.Add(catalogId);
            }
        }

        // 构建树形结构：将子节点挂载到父节点
        foreach (var catalog in allCatalogs)
        {
            var catalogId = catalog.Id;
            var parentId = catalog.ParentId;

            if (parentId > 0 && catalogDict.ContainsKey(parentId) && catalogDict.ContainsKey(catalogId))
            {
                var parentNode = catalogDict[parentId];
                var childNode = catalogDict[catalogId];

                if (!parentNode.Child.Any(c => c.Id == childNode.Id))
                {
                    parentNode.Child.Add(childNode);
                }
            }
        }

        // 计算每个节点的层级并返回根节点列表
        var result = rootCatalogIds
            .Where(id => catalogDict.ContainsKey(id))
            .Select(id =>
            {
                var node = catalogDict[id];
                node.Level = 1;
                CalculateChildLevels(node.Child, 2);
                return node;
            })
            .ToList();

        return result;
    }

    /// <summary>
    /// 递归计算子节点层级
    /// </summary>
    private void CalculateChildLevels(List<IcrJournalCatalogTreeDto> children, int level)
    {
        foreach (var child in children)
        {
            child.Level = level;
            if (child.Child != null && child.Child.Count > 0)
            {
                CalculateChildLevels(child.Child, level + 1);
            }
        }
    }

    /// <summary>
    /// 导入书籍目录
    /// </summary>
    /// <param name="JournalId"></param>
    /// <param name="dtos"></param>
    /// <returns></returns>
    public async Task<bool> ImportCatalogAsync(long JournalId, List<JournalCatalogTreeListDto> dtos)
    {
        dtos = dtos.Where(c => !string.IsNullOrWhiteSpace(c.Name)).ToList();
        BusinessException.ThrowIf(dtos.Select(c => c.PageNum).Distinct().Count() != dtos.Count(), "存在重复的页码", ResultCode.CONFLICT);

        var Journal = await Queryable<Journal>().Where(w => w.Id == JournalId).FirstAsync();
        BusinessException.ThrowIf(Journal.IsNull(), "未找到书本", ResultCode.NOT_FOUND);
        var pageNums = dtos.Select(c => c.PageNum).ToList();
        var pageNumNotExists = await _JournalPageRepository.Queryable().AnyAsync(w => w.JournalId == JournalId && !pageNums.Contains(w.PageNum));
        BusinessException.ThrowIf(pageNumNotExists, "不存在的书页", ResultCode.NOT_FOUND);

        var firstCatelogGroup = dtos.Select(c => c.ParentName).Distinct().Select(c => new JournalCatalog
        {
            JournalId = JournalId,
            Id = YitIdHelper.NextId(),
            Level = 1,
            Name = c,
        }).ToList();
        var subCatelogGroup = dtos.Select(c => new { c.Name, c.ParentName }).Distinct().Select(c => new
        {
            JournalId = JournalId,
            Id = YitIdHelper.NextId(),
            Level = 2,
            Name = c.Name,
            ParentId = firstCatelogGroup.FirstOrDefault(m => m.Name == c.ParentName)?.Id,
            ParentName = c.ParentName
        }).ToList();

        var result = await UseTranAsync(async () =>
        {
            await base.DeleteAsync(c => c.JournalId == JournalId);
            await base.InsertRangeAsync(firstCatelogGroup);
            await base.InsertRangeAsync(subCatelogGroup.Adapt<List<JournalCatalog>>());
            var JournalPages = await Queryable<JournalPage>().Where(c => c.JournalId == JournalId).ToListAsync();
            JournalPages.ForEach(c =>
            {
                var cate = dtos.FirstOrDefault(m => m.PageNum == c.PageNum);
                c.JournalCatalogId = subCatelogGroup?.FirstOrDefault(m => m.Name == cate?.Name && m.ParentName == cate?.ParentName)?.Id ?? 0;
            });
            await base.Context.Updateable<JournalPage>(JournalPages).UpdateColumns(c => c.JournalCatalogId).ExecuteCommandAsync();
            return true;
        });

        return result;
    }

    public async Task<long> InsertAsync(JournalCatalogInput input)
    {
        var map = input.Adapt<JournalCatalog>();
        map.Id = YitIdHelper.NextId();
        await UseTranAsync(async () =>
        {
            // 获取同级所有节点
            var siblings = await base.Queryable().Where(w => w.JournalId == input.JournalId).Where(w => w.ParentId == input.ParentId).OrderBy(o => o.Sort).ToListAsync();

            if (input.Position.HasValue && input.Position > 0 && input.Position <= siblings.Count)
            {
                // 调换位置,前面不变,后续加1即可
                int validPosition = Math.Min(input.Position.Value, siblings.Count);
                map.Sort = validPosition;

                // 调整后续节点的SortOrder (+1)
                await base.Updateable()
                    .SetColumns(x => x.Sort == x.Sort + 1)
                    .Where(x => x.ParentId == input.ParentId && x.Sort >= validPosition)
                    .ExecuteCommandAsync();
            }
            else
            {
                // 默认追加到末尾
                map.Sort = siblings.Count > 0 ? siblings.Max(x => x.Sort) + 1 : 0;
            }


            var data = await base.InsertAsync(map);

            if (input.Type == 1)
            {
                var Journal = await Queryable<Journal>().Where(w => w.Id == input.JournalId).FirstAsync();
                BusinessException.ThrowIf(Journal.IsNull(), "未找到书本", ResultCode.NOT_FOUND);

                //var dotMatrixPage = new DotMatrixPage()
                //{
                //    Id = YitIdHelper.NextId(),
                //    DotMatrixNoteJournalId = input.JournalId,
                //    WidthMilliMeter = Journal.Width,
                //    HightMilliMeter = Journal.Height,
                //};
                var JournalPage = new JournalPage
                {
                    JournalId = input.JournalId,
                    JournalCatalogId = map.Id,
                    //DotMatrixPageId = dotMatrixPage.Id,
                    PageNum = map.Sort,
                };
            }
        });
        return map.Id;

    }

    public async Task<bool> UpdateAsync(JournalCatalogUpdateInput input)
    {
        var result = await base.Updateable(input.Adapt<JournalCatalog>()).Where(w => w.Id == input.Id).ExecuteCommandAsync() > 0;

        return result;
    }

    public async Task<bool> DeleteAsync(long id)
    {
        var catas = await base.Queryable().ToChildListAsync(it => it.ParentId, id);
        var ids = catas.Select(s => s.Id).ToList();

        await UseTranAsync(async () =>
        {
            // 删除目录
            var cata = await base.Deleteable().Where(d => ids.Contains(d.Id)).ExecuteCommandAsync() > 0;
            BusinessException.ThrowIf(!cata, $"删除目录失败", ResultCode.GLOBAL_ERROR);
            // 删除所有页/问题
            var pages = await _JournalPageRepository.DeleteAsync(w => ids.Contains(w.JournalCatalogId));
            BusinessException.ThrowIf(pages.IsNull(), $"删除数据失败", ResultCode.GLOBAL_ERROR);


            //var x = await _JournalPageRepository.DeleteAsync(w => ids.Contains(w.JournalCatalogId));
            //var y = await _JournalPageTaskRepository.DeleteAsync(w => ids.Contains(w.JournalCatalogId));
        });
        return true;
    }

    public async Task<bool> MoveAsync(MoveInput input)
    {
        // 1. 获取源节点并校验
        var sourceNode = await base.Queryable().Where(x => x.Id == input.SourceId).FirstAsync();
        BusinessException.ThrowIf(sourceNode.IsNull(), $"要移动的节点{input.SourceId}不存在", ResultCode.NOT_FOUND);


        // 2. 校验目标父节点（如果指定）
        if (input.TargetParentId > 0)
        {
            var targetParentExists = await base.Queryable().Where(x => x.Id == input.TargetParentId).AnyAsync();
            BusinessException.ThrowIf(!targetParentExists, $"目标父节点{input.TargetParentId}不存在", ResultCode.NOT_FOUND);
        }

        await base.UseTranAsync(async () =>
        {
            //var tree = await base.Queryable().Where(x => x.Id == input.SourceId).AsTreeCte().OrderBy(x => x.Level).ToTreeListAsync();

            if (input.Position.HasValue)
            {
                await base.Updateable()
                      .SetColumns(x => x.Sort == x.Sort + 1)
                      .Where(x => x.ParentId == input.TargetParentId && x.Sort >= input.Position.Value)
                      .ExecuteCommandAsync();
            }

            // 3. 更新源节点的父节点
            var updateCount = await base.Updateable()
                .SetColumns(x => x.ParentId, input.TargetParentId)
                .SetColumns(x => x.Sort, input.Position ?? 0)
                .Where(x => x.Id == input.SourceId)
                .ExecuteCommandAsync() > 0;

            BusinessException.ThrowIf(!updateCount, $"节点移动失败");
        });

        return true;
    }


    //public async Task<bool> CopyAsync(CopyInput input)
    //{

    //    // 1. 获取源节点并校验
    //    var sourceNode = await base.Queryable().Where(x => x.Id == input.SourceId).FirstAsync();
    //    BusinessException.ThrowIf(sourceNode.IsNull(), $"要移动的节点{input.SourceId}不存在");


    //    // 2. 校验目标父节点（如果指定）
    //    if (input.TargetParentId > 0)
    //    {
    //        var targetParentExists = await base.Queryable().Where(x => x.Id == input.TargetParentId).AnyAsync();
    //        BusinessException.ThrowIf(!targetParentExists, $"目标父节点{input.TargetParentId}不存在");
    //    }

    //    using var uow = _unitOfWorkManager.Begin();
    //    var tree = await base.Queryable().IncludeMany(c => c.Pages, then => then.IncludeMany(x => x.PageTasks))
    //              .Where(x => x.Id == input.SourceId)
    //              .AsTreeCte()
    //              .OrderBy(x => x.Level)
    //              .ToTreeListAsync();

    //    if (input.Position.HasValue)
    //    {
    //        await base.Updateable()
    //              .Set(x => x.Sort + 1)
    //              .Where(x => x.ParentId == input.TargetParentId && x.Sort >= input.Position.Value)
    //              .ExecuteCommandAsync();
    //    }

    //    var copy = await DeepCopyAsync(tree.First(), input.TargetParentId);
    //    BusinessException.ThrowIf(copy.IsNull(), $"复制节点失败");

    //    var data = await base.InsertAsync(copy);
    //    BusinessException.ThrowIf(data.IsNull(), $"复制节点失败");

    //    var pages = copy.Where(s => s.Pages.NotNull()).Queryable()Many(s => s.Pages);
    //    var tempPage = await _JournalPageRepository.InsertAsync(pages);
    //    BusinessException.ThrowIf(tempPage.IsNull(), $"复制页面数据失败");

    //    //var task = pages.Where(w => w.PageTasks.NotNull()).Queryable()Many(s => s.PageTasks);
    //    //var tempPageTask = await _JournalPageTaskRepository.InsertAsync(task);
    //    //BusinessException.ThrowIf(tempPageTask.IsNull(), $"复制页面问题数据失败");

    //    uow.Commit();
    //    return true;
    //}
    //private async Task<List<IcrJournalCatalog>> DeepCopyAsync(IcrJournalCatalog source, long targetParentId, List<IcrJournalCatalog>? list = null)
    //{
    //    list ??= new List<IcrJournalCatalog>();

    //    var copy = new IcrJournalCatalog
    //    {
    //        Id = YitIdHelper.NextId(),// 设置新ID
    //        Name = !list.Any() ? $"{source.Name} 副本" : source.Name,
    //        ParentId = targetParentId,
    //        Level = source.Level,
    //        Sort = source.Sort,
    //    };
    //    copy.Pages?.ForEach(page =>
    //    {
    //        page.Id = YitIdHelper.NextId(); // 设置新页面ID
    //        page.JournalCatalogId = copy.Id; // 设置为新目录的ID
    //        page.PageTasks?.ForEach(task =>
    //        {
    //            task.Id = YitIdHelper.NextId(); // 设置新问题ID
    //            task.JournalPageId = page.Id; // 设置为新页面的ID
    //        });
    //    });
    //    list.Add(copy);

    //    // 递归复制子节点
    //    if (source.Childs != null && source.Childs.Any())
    //    {
    //        foreach (var child in source.Childs)
    //        {
    //            await DeepCopyAsync(child, copy.Id, list);
    //        }
    //    }
    //    return list;
    //}
}
