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

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

        public CategoryController(ILogger<CategoryController> 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 GetCategoryTree()
        {
            var data = _dbContext.Categories.Where(p => p.Enabled).ToList();

            var categoryItems = new List<CategoryItem>();
            var categories = BuildMenus(categoryItems, data, 0, true);
            var result = new ApiResult<List<CategoryItem>>().IsSuccess(categories);
            return new JsonResult(result);
        }

        /// <summary>
        /// 可用的分类树结构
        /// </summary>
        /// <returns></returns>
        [HttpGet("items")]
        //[ResponseCache(VaryByHeader = "User-Agent", Duration = 30)]
        public IActionResult GetCategoryForSelected()
        {
            var data = _dbContext.Categories.Where(p => p.Enabled).ToList();

            var categoryItems = new List<CategoryItem>();
            var categories = BuildMenus(categoryItems, data, 0, false);
            var result = new ApiResult<List<CategoryItem>>().IsSuccess(categories);
            return new JsonResult(result);
        }

        /// <summary>
        /// 分类列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("list")]
        public IActionResult GetCategories()
        {
            var data = _dbContext.Categories.ToList();

            var categoryItems = new List<CategoryItem>();
            var categories = BuildMenus(categoryItems, data, 0, false);
            var result = new ApiResult<List<CategoryItem>>().IsSuccess(categories);
            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(CategorySearch search, int page, int size = 20)
        {
            var result = new ApiResult<PagingList<Category>>();
            try
            {
                var pager = new PagingList<Category>() { Size = size, Index = page < 1 ? 1 : page };

                var query = from p in _dbContext.Categories
                            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<Category>();
            try
            {
                var data = _dbContext.Categories.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(CategoryModel model)
        {
            var result = new ApiResult<string>();
            var validator = new CategoryModelValidator();
            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
            {
                model.Id = _idCreator.NewId();

                var data = _mapper.Map<Category>(model);
                data.CreateTime = DateTime.UtcNow;

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

                _dbContext.Categories.Add(data);
                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(CategoryModel model)
        {
            var result = new ApiResult<string>();
            var validator = new CategoryModelValidator();
            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.Categories.Where(p => p.Id == model.Id).SingleOrDefault();
            if (data == null)
            {
                result = result.IsFail("目标数据不存在");
            }
            else
            {
                data = _mapper.Map(model, data);
                data.UpdateTime = DateTime.UtcNow;

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

                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.Categories.Where(p => p.Id == id).SingleOrDefault();
                if (menu != null)
                {
                    _dbContext.Categories.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<CategoryItem> BuildMenus(List<CategoryItem> menus, List<Category> 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<CategoryItem>(menu);
                var children = sourceMenus.Count(p => p.ParentId == menu.Id);
                if (children > 0)
                {
                    var childrenMenus = new List<CategoryItem>();
                    var childrenList = BuildMenus(childrenMenus, sourceMenus, menu.Id, tree);
                    if (tree)
                    {
                        data.Children.AddRange(childrenList);
                        menus.Add(data);
                    }
                    else
                    {
                        menus.Add(data);
                        foreach (var child in childrenList)
                        {
                            menus.Add(child);
                        }
                    }
                }
                else
                {
                    data.IsLast = true;
                    menus.Add(data);
                }
            }
            return menus;
        }
    }
}
