using Atomx.Admin.Client.Models;
using Atomx.Admin.Client.Validators;
using Atomx.Admin.Services;
using Atomx.Common.Entities;
using Atomx.Common.Enums;
using Atomx.Common.Models;
using Atomx.Data;
using Atomx.Data.CacheServices;
using Atomx.Data.Services;
using Mapster;
using MapsterMapper;
using Microsoft.AspNetCore.Mvc;

namespace Atomx.Admin.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class MenuController : ControllerBase
    {
        readonly ILogger<MenuController> _logger;
        readonly IdentityService _identityService;
        readonly IIdCreatorService _idCreator;
        readonly IMapper _mapper;
        readonly DataContext _dbContext;
        readonly JwtSetting _jwtSetting;
        readonly ICacheService _cacheService;

        public MenuController(ILogger<MenuController> logger, IdentityService identityService, IIdCreatorService idCreator, IMapper mapper, DataContext dbContext, JwtSetting jwtSetting, ICacheService cacheService)
        {
            _logger = logger;
            _identityService = identityService;
            _idCreator = idCreator;
            _mapper = mapper;
            _dbContext = dbContext;
            _jwtSetting = jwtSetting;
            _cacheService = cacheService;
        }

        /// <summary>
        /// 获取用于菜单结构的树形数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("tree")]
        //[ResponseCache(VaryByHeader = "User-Agent", Duration = 30)]
        public IActionResult GetMenus()
        {
            var data = GetSystemMenu();

            var menus = new List<MenuItem>();
            var menuItems = BuildMenus(menus, data, 0, true);
            var config = new TypeAdapterConfig();
            config.NewConfig<MenuItem, AntDesign.ProLayout.MenuDataItem>().Map(src => src.Path, dest => dest.Url);
            var menuTree = menuItems.Adapt<List<AntDesign.ProLayout.MenuDataItem>>(config);
            var result = new ApiResult<List<AntDesign.ProLayout.MenuDataItem>>().IsSuccess(menuTree);
            return new JsonResult(result);
        }

        /// <summary>
        /// 获取菜单数据管理可用的数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("list")]
        public IActionResult GetMenuList()
        {
            var data = _dbContext.Menus.Where(p => p.Type == (int)MenuType.AdminSystem).ToList();

            var menus = new List<MenuItem>();
            var menuItems = BuildMenus(menus, data, 0, false);
            var result = new ApiResult<List<MenuItem>>().IsSuccess(menuItems);
            return new JsonResult(result);
        }

        /// <summary>
        /// 查询接口
        /// </summary>
        /// <param name="search"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        [HttpPost("search")]
        public IActionResult Search(MenuSearch search, int page, int size = 20)
        {
            var result = new ApiResult<PagingList<Menu>>();
            try
            {
                var pager = new PagingList<Menu>() { Size = size, Index = page < 1 ? 1 : page };

                var query = from p in _dbContext.Menus
                            select p;
                if (!string.IsNullOrEmpty(search.Name))
                {
                    query = from p in query
                            where p.Name.Contains(search.Name)
                            select p;
                }
                pager.Count = query.Count();
                pager.Items = query.OrderByDescending(p => p.CreateTime).Skip((pager.Index - 1) * size).Take(size).ToList();

                result = result.IsSuccess(pager);
            }
            catch (Exception ex)
            {
                result = result.IsFail(ex.Message);
                _logger.LogError(ex.Message);
            }
            return new JsonResult(result);
        }

        /// <summary>
        /// 根据id获取数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id:long}")]
        public IActionResult Get(long id)
        {
            var result = new ApiResult<Menu>();
            try
            {
                var data = _dbContext.Menus.Where(p => p.Id == id).SingleOrDefault();
                result = result.IsSuccess(data);
            }
            catch (Exception ex)
            {
                result = result.IsFail(ex.Message);
                _logger.LogError(ex.Message);
            }
            return new JsonResult(result);
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost("add")]
        public IActionResult Add(MenuModel model)
        {
            var result = new ApiResult<string>();
            var validator = new MenuModelValidator();
            var validation = validator.Validate(model);
            if (!validation.IsValid)
            {
               
                var message = validation.Errors.FirstOrDefault()?.ErrorMessage;
                result = result.IsFail(message ?? string.Empty, null);
                return new JsonResult(result);
            }
            try
            {
                var data = _dbContext.Menus.Where(p => p.Id == model.ParentId).SingleOrDefault();
                if (data == null)
                {
                    model.Depth = 0;
                    model.Path = model.Id.ToString();
                }
                else
                {
                    model.Depth = data.Depth + 1;
                    model.Path = $"{data.Path},{model.Id}";
                }
                model.Id = _idCreator.NewId();

                var menu = _mapper.Map<Menu>(model);
                menu.CreateTime = DateTime.UtcNow;

                _dbContext.Menus.Add(menu);
                int count = _dbContext.SaveChanges();

                result = result.IsSuccess(count.ToString());
            }
            catch (Exception ex)
            {
                result = result.IsFail(ex.Message);
                _logger.LogError(ex.Message);
            }
            return new JsonResult(result);
        }

        /// <summary>
        /// 编辑数据
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost("edit")]
        public IActionResult Edit(MenuModel model)
        {
            var result = new ApiResult<string>();
            var validator = new MenuModelValidator();
            var validation = validator.Validate(model);
            if (!validation.IsValid)
            {
                var message = validation.Errors.FirstOrDefault()?.ErrorMessage;
                result = result.IsFail(message ?? string.Empty, null);
                return new JsonResult(result);
            }

            var data = _dbContext.Menus.Where(p => p.Id == model.ParentId).SingleOrDefault();
            if (data == null)
            {
                model.Depth = 0;
                model.Path = model.Id.ToString();
            }
            else
            {
                model.Depth = data.Depth + 1;
                model.Path = $"{data.Path},{model.Id}";
            }

            var menu = _dbContext.Menus.Where(p => p.Id == model.Id).SingleOrDefault();
            if (menu == null)
            {
                result = result.IsFail("目标数据不存在");
            }
            else
            {
                menu = _mapper.Map(model, menu);
                menu.UpdateTime = DateTime.UtcNow;
                try
                {
                    int count = _dbContext.SaveChanges();
                    result = result.IsSuccess(count.ToString());
                }
                catch (Exception ex)
                {
                    result = result.IsFail(ex.Message);
                    _logger.LogError(ex.Message);
                }
            }
            return new JsonResult(result);
        }

        /// <summary>
        /// 删除指定ID的数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost("delete/{id:long}")]
        public IActionResult Delete(long id)
        {
            var result = new ApiResult<string>();
            try
            {
                var menu = _dbContext.Menus.Where(p => p.Id == id).SingleOrDefault();
                if (menu != null)
                {
                    _dbContext.Menus.Remove(menu);
                    int count = _dbContext.SaveChanges();
                    result = result.IsSuccess(count.ToString());
                }
            }
            catch (Exception ex)
            {
                result = result.IsFail(ex.Message);
                _logger.LogError(ex.Message);
            }
            return new JsonResult(result);
        }

        private List<Menu> GetSystemMenu()
        {
            return _dbContext.Menus.Where(p => p.Type == (int)MenuType.AdminSystem).ToList();
        }

        private List<MenuItem> BuildMenus(List<MenuItem> menus, List<Menu> sourceMenus, long parentId, bool tree = false)
        {
            var list = sourceMenus.Where(p => p.ParentId == parentId).OrderBy(p => p.DisplayOrder).ToList();

            foreach (var menu in list)
            {
                var data = _mapper.Map<MenuItem>(menu);
                var children = sourceMenus.Count(p => p.ParentId == menu.Id);
                if (children > 0)
                {
                    var childrenMenus = new List<MenuItem>();
                    var childrenList = BuildMenus(childrenMenus, sourceMenus, menu.Id, true);
                    if (tree)
                    {
                        if (data.Children == null)
                        {
                            data.Children = new List<MenuItem>();
                        }
                        data.Children.AddRange(childrenList);
                        menus.Add(data);
                    }
                    else
                    {
                        menus.Add(data);
                        foreach (var child in childrenList)
                        {
                            menus.Add(child);
                        }
                    }
                }
                else
                {
                    menus.Add(data);
                }
            }
            return menus;
        }
    }
}
