using Hotline.Share.Dtos.FlowEngine.Definition;
using Hotline.Share.Enums.FlowEngine;
using MapsterMapper;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.FlowEngine.Definitions;

public class DefinitionDomainService : IDefinitionDomainService, IScopeDependency
{
    private readonly IRepository<WorkflowDefinition> _definitionRepository;
    private readonly IMapper _mapper;

    public DefinitionDomainService(IRepository<WorkflowDefinition> definitionRepository, IMapper mapper)
    {
        _definitionRepository = definitionRepository;
        _mapper = mapper;
    }

    /// <summary>
    /// 新增流程模板草稿
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<string> AddAsync(AddDefinitionDto dto, CancellationToken cancellationToken)
    {
        var definition = _mapper.Map<WorkflowDefinition>(dto);
        return await _definitionRepository.AddAsync(definition, cancellationToken);
    }

    /// <summary>
    /// 发布流程模板
    /// </summary>
    /// <param name="id"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task PublishAsync(string id, CancellationToken cancellationToken)
    {
        var definitionTemp = await _definitionRepository.GetAsync(id, cancellationToken);
        if (definitionTemp == null)
            throw UserFriendlyException.SameMessage("无效模板编号");
        if (definitionTemp.Status != EDefinitionStatus.Temporary)
            throw UserFriendlyException.SameMessage("非草稿模板不允许发布");

        ValidateDefinition(definitionTemp);

        var lastVersion = await GetLastVersionNoAsync(definitionTemp.Code, cancellationToken);
        definitionTemp.Version = lastVersion + 1;
        definitionTemp.Status = EDefinitionStatus.Enable;

        //await EnableAsync(definitionTemp.ModuleCode!, cancellationToken);

        await _definitionRepository.UpdateAsync(definitionTemp, cancellationToken);
    }

    ///// <summary>
    ///// 禁用指定业务模块下所有模板
    ///// </summary>
    ///// <param name="moduleCode"></param>
    ///// <param name="cancellationToken"></param>
    ///// <returns></returns>
    //public async Task EnableAsync(string moduleCode, CancellationToken cancellationToken)
    //{
    //    if (string.IsNullOrEmpty(moduleCode))
    //        throw new UserFriendlyException("moduleCode为空");
    //    var definitions = await _definitionRepository.QueryAsync(d =>
    //        d.ModuleCode == moduleCode && d.Status == EDefinitionStatus.Enable);
    //    definitions.ForEach(d => d.Status = EDefinitionStatus.Disable);
    //    await _definitionRepository.UpdateRangeAsync(definitions, cancellationToken);
    //}

    /// <summary>
    /// 发布（保存并发布）
    /// </summary>
    public async Task PublishAsync(AddDefinitionDto dto, CancellationToken cancellationToken)
    {
        var id = await AddAsync(dto, cancellationToken);
        await PublishAsync(id, cancellationToken);
    }

    /// <summary>
    /// 查询最大版本号（含启用、禁用）
    /// </summary>
    /// <param name="code"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<int> GetLastVersionNoAsync(string code, CancellationToken cancellationToken)
    {
        return await _definitionRepository.Queryable()
            .Where(d => d.Code == code)
            .MaxAsync(d => d.Version);

        //var definition = await GetLastVersionDefinitionAsync(code, enable, cancellationToken);
        //return definition?.Version ?? 0;
    }

    ///// <summary>
    ///// 查询最新版本
    ///// </summary>
    ///// <param name="moduleCode"></param>
    ///// <param name="cancellationToken"></param>
    ///// <returns></returns>
    //public async Task<Definition?> GetLastVersionByModuleCodeAsync(string moduleCode, CancellationToken cancellationToken)
    //{
    //    return await _definitionRepository.Queryable()
    //        .Where(d => d.ModuleCode == moduleCode)
    //        .OrderByDescending(d => d.Version)
    //        .Take(1)
    //        .FirstAsync();
    //}

    /// <summary>
    /// 查询最新版本
    /// </summary>
    /// <param name="code"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<WorkflowDefinition?> GetLastVersionAsync(string code, CancellationToken cancellationToken)
    {
        return await _definitionRepository.Queryable()
            .Where(d => d.Code == code)
            .OrderByDescending(d => d.Version)
            .Take(1)
            .FirstAsync();
    }

    #region private

    private void ValidateDefinition(WorkflowDefinition? definition)
    {
        if (definition is null)
            throw new UserFriendlyException("无效 Definition Id");
        if (definition.Code == null)
            throw UserFriendlyException.SameMessage("无效Code");
        if (definition.Status is not EDefinitionStatus.Temporary)
            throw UserFriendlyException.SameMessage("只能发布草稿状态的模板");
        if (!definition.Steps.Any())
            throw UserFriendlyException.SameMessage("未配置流程节点");
        var startSteps = definition.Steps.Where(d => d.StepType == EStepType.Start).ToList();
        if (!startSteps.Any())
            throw UserFriendlyException.SameMessage("未配置开始节点");
        if (startSteps.Count > 1)
            throw UserFriendlyException.SameMessage("开始节点只能有一个");

        var endSteps = definition.Steps.Where(d => d.StepType == EStepType.End).ToList();
        if (!endSteps.Any())
            throw UserFriendlyException.SameMessage("未配置结束节点");
        if (endSteps.Count > 1)
            throw UserFriendlyException.SameMessage("结束节点只能有一个");

        foreach (var step in definition.Steps)
        {
            if (step.StepType != EStepType.End && !step.NextSteps.Any())
                throw UserFriendlyException.SameMessage($"{step.Code}节点未配置下一节点");
        }

        if (definition.Steps.GroupBy(d => d.Code).Count() < definition.Steps.Count)
            throw UserFriendlyException.SameMessage("一个模板内不允许出现code相同的节点");

        //if (definition.Steps.Count(d => d.NextSteps.Any(x => x.Code == "End")) > 1)
        //    throw UserFriendlyException.SameMessage("结束节点只能有一个上级节点");

        //var startStep = startSteps.First();
        //if (startStep.NextSteps.Count > 1)
        //    throw UserFriendlyException.SameMessage("开始节点有且只能有一个下级节点");
    }

    #endregion
}