using Hotline.Api.Filter;
using Hotline.Application.FlowEngine;
using Hotline.Application.OrderApp;
using Hotline.Configurations;
using Hotline.File;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.Orders;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Enums.Order;
using Hotline.Tools;
using MapsterMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using SqlSugar;
using XF.Domain.Authentications;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using XF.Utility.EnumExtensions;

namespace Hotline.Api.Controllers
{
    /// <summary>
    /// 终止管理
    /// </summary>
    public class OrderTerminateController : BaseController
    {
        private readonly ISessionContext _sessionContext;
        private readonly IMapper _mapper;
        private readonly IFileRepository _fileRepository;
        private readonly IWorkflowApplication _workflowApplication;
        private readonly IRepository<Workflow> _workflowRepository;
        private readonly IWorkflowDomainService _workflowDomainService;
        private readonly IOrderRepository _orderRepository;
        private readonly IOrderDomainService _orderDomainService;
        private readonly IOrderTerminateRepository _orderTerminateRepository;
        private readonly IOrderApplication _orderApplication;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;

        public OrderTerminateController(
            ISessionContext sessionContext,
            IMapper mapper,
            IFileRepository fileRepository,
            IWorkflowApplication workflowApplication,
            IRepository<Workflow> workflowRepository,
            IWorkflowDomainService workflowDomainService,
            IOrderRepository orderRepository,
            IOrderDomainService orderDomainService,
            IOrderTerminateRepository orderTerminateRepository,
            IOrderApplication orderApplication,
             IOptionsSnapshot<AppConfiguration> appOptions
            )
        {
            _sessionContext = sessionContext;
            _mapper = mapper;
            _fileRepository = fileRepository;
            _workflowApplication = workflowApplication;
            _workflowRepository = workflowRepository;
            _workflowDomainService = workflowDomainService;
            _orderRepository = orderRepository;
            _orderDomainService = orderDomainService;
            _orderTerminateRepository = orderTerminateRepository;
            _orderApplication = orderApplication;
            _appOptions = appOptions;

        }

        /// <summary>
        /// 工单终止待申请列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("may-terminate")]
        public async Task<PagedDto<OrderDto>> MayOrderTerminateList([FromQuery] OrderTerminateListDto dto)
        {
            var isAdmin = _orderDomainService.IsCheckAdmin();
            var (total, items) = await _orderRepository.Queryable(isAdmin: isAdmin)
                .Includes(d => d.OrderTerminates)
                .WhereIF(_appOptions.Value.IsZiGong, d => d.Source != ESource.ProvinceStraight)//自贡任务  495 终止申请页面只显示市工单
                .Where(d => SqlFunc.Subqueryable<OrderTerminate>().Where(t => t.OrderId == d.Id && t.Status != ETerminateStatus.SendBackStart).NotAny())
                .Where(d => d.Status >= EOrderStatus.Filed && d.ActualHandleOrgCode.StartsWith(_sessionContext.OrgId))
                .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No!.Contains(dto.No!))
                .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
                .WhereIF(dto.ApplyStartTime.HasValue && dto.ApplyEndTime.HasValue,
                    d => d.OrderTerminates.Any(t => t.CreationTime >= dto.ApplyStartTime && t.CreationTime <= dto.ApplyEndTime))
                .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, d => d.StartTime >= dto.StartTime && d.StartTime <= dto.EndTime)
                .OrderByDescending(d => d.StartTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
        }


        /// <summary>
        /// 工单终止列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<PagedDto<OrderTerminateEntityDto>> OrderTerminateList([FromQuery] OrderTerminateListDto dto)
        {
            var (total, items) = await _orderApplication.OrderTerminateList(dto)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
            return new PagedDto<OrderTerminateEntityDto>(total, _mapper.Map<IReadOnlyList<OrderTerminateEntityDto>>(items));
        }

        /// <summary>
        /// 工单终止列表导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>

        [HttpPost("export")]
        public async Task<FileStreamResult> OrderTerminateListExport([FromBody] ExportExcelDto<OrderTerminateListDto> dto)
        {
            var query = _orderApplication.OrderTerminateList(dto.QueryDto);
            List<OrderTerminate> data;
            if (dto.IsExportAll)
            {
                data = await query.ToListAsync(HttpContext.RequestAborted);
            }
            else
            {
                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
                data = items;
            }

            var dataDtos = _mapper.Map<ICollection<OrderTerminateEntityDto>>(data);

            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderTerminateEntityDto>(dto.ColumnInfos);

            var dtos = dataDtos
                .Select(stu => _mapper.Map(stu, typeof(OrderTerminateEntityDto), dynamicClass))
                .Cast<object>()
                .ToList();

            var stream = ExcelHelper.CreateStream(dtos);

            return ExcelStreamResult(stream, "工单终止列表");
        }


        /// <summary>
        /// 开始工单终止流程
        /// </summary>
        [HttpPost("startflow")]
        [LogFilter("开始工单终止流程")]
        public async Task StartFlow([FromBody] StartWorkflowDto<OrderTerminateDto> dto)
        {
            var screenAny = await _orderTerminateRepository.AnyAsync(x =>
                x.OrderId == dto.Data.OrderId && x.Status == ETerminateStatus.Approval);
            if (screenAny)
                throw UserFriendlyException.SameMessage("该工单已提起终止申请，正在审批过程中，不能申请");

            var isNoPass = await _orderTerminateRepository.AnyAsync(x => x.Status == ETerminateStatus.Refuse && x.OrderId == dto.Data.OrderId);
            if (isNoPass)
                throw UserFriendlyException.SameMessage("该工单已被拒绝过终止申请，不能再次申请");

            var model = _mapper.Map<OrderTerminate>(dto.Data);
            model.Status = ETerminateStatus.Approval;
            model.InitId();
            if (dto.Data.Files.Any())
                model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
            else
                model.FileJson = new List<Share.Dtos.File.FileJson>();
            await _orderTerminateRepository.AddAsync(model, HttpContext.RequestAborted);
            try
            {
                var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderTerminate;
                startDto.Opinion = dto.Data.Content;
                startDto.Title = "申请终止流程";
                // await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
                // await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
                await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
            }
            catch (Exception e)
            {
                await _orderTerminateRepository.RemoveAsync(model.Id);
                model.Id = string.Empty;
                throw new UserFriendlyException($"工单开启终止流程失败!, {e.Message}", "工单开启终止流程失败");
            }
        }


        /// <summary>
        /// 工单终止修改后下一步流程
        /// </summary>
        [HttpPost("initial_nextFlow")]
        [LogFilter("办理工单终止流程")]
        public async Task InitialNextFlow([FromBody] TerminateNextFlowDto dto)
        {
            var model = await _orderTerminateRepository.GetAsync(dto.Data.Id);

            if (dto.Data.Files.Any())
                model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
            else
                model.FileJson = new List<Share.Dtos.File.FileJson>();

            model.Status = ETerminateStatus.Approval;
            model.Content = dto.Data.Content;
            model.IsRecommit = true;
            await _orderTerminateRepository.UpdateAsync(model, HttpContext.RequestAborted);
            try
            {
                dto.NextWorkflow.WorkflowId = model.WorkflowId;
                await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
            }
            catch (Exception e)
            {
                throw new UserFriendlyException($"工单终止下一步流程失败!, {e.Message}", "工单终止下一步流程失败");
            }
        }

        /// <summary>
        /// 查询工单终止流程开启参数
        /// </summary>
        /// <returns></returns>
        [HttpGet("screen/startflow")]
        public async Task<NextStepsDto> GetTerminateFlowStartOptionsAsync()
        {
            return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderTerminate,
                HttpContext.RequestAborted);
        }

        /// <summary>
        /// 查询工单终止流程参数
        /// </summary>
        /// <returns></returns>
        [HttpGet("workflow/{id}")]
        public async Task<string> GetTerminateWorkFlowAsync(string id)
        {
            var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id);
            return workflow.Id;
        }

        /// <summary>
        ///  甄别查询流程办理下一步可选节点
        /// </summary>
        /// <param name="workflowId"></param>
        /// <returns></returns>
        [HttpGet("{workflowId}/nextsteps")]
        public async Task<NextStepsDto> OrderTerminateNextsteps(string workflowId)
        {
            return await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 终止详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<OrderTerminateEntityDto> Entity(string id)
        {
            var model = await _orderTerminateRepository.Queryable()
                .Includes(x => x.Order)
                .Includes(x => x.Workflow, d => d.Steps)
                .FirstAsync(x => x.Id == id);
            var rspModel = _mapper.Map<OrderTerminateEntityDto>(model);
            rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
                _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
            if (model.Status == ETerminateStatus.SendBackStart)
                rspModel.IsCanHandle = false;
            rspModel.Handle = false;
            if (!string.IsNullOrEmpty(rspModel.WorkflowId))
            {
                rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
                    _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
            }

            if (rspModel.FileJson != null && rspModel.FileJson.Any())
            {
                var ids = rspModel.FileJson.Select(x => x.Id).ToList();
                rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
            }
            return rspModel;
        }

        /// <summary>
        /// 列表页面基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("base")]
        public async Task<object> BaseData()
        {
            var rsp = new
            {
                Status = EnumExts.GetDescriptions<ETerminateStatus>(),
            };
            return rsp;
        }

        /// <summary>
        /// 终止修改理由
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("update_content")]
        [LogFilter("终止修改理由")]
        public async Task Update([FromBody] OrderTerminateContentDto dto)
        {
            await _orderTerminateRepository.Updateable().SetColumns(x => new OrderTerminate { Content = dto.Content }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
        }

    }
}
