using Hotline.FlowEngine.Definitions;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.File;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.FlowEngine.Definition;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Order;
using SqlSugar;
using XF.Domain.Entities;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.FlowEngine.Workflows;

public abstract class StepBasicEntity : CreationEntity
{
    public string WorkflowId { get; set; }

    /// <summary>
    /// 业务唯一标识
    /// </summary>
    public string? ExternalId { get; set; }

    #region 业务模块(冗余)

    public string? ModuleId { get; set; }

    public string? ModuleName { get; set; }

    public string? ModuleCode { get; set; }

    #endregion

    /// <summary>
    /// 流程指派类型
    /// </summary>
    public EFlowAssignType? FlowAssignType { get; set; }

    /// <summary>
    /// 该节点指派办理对象（依据不同指派方式可能为：orgId或userId）,该字段subStep才会存在，stepBox不存在
    /// 采用list类型，兼容或签
    /// </summary>
    [SugarColumn(ColumnDataType = "json", IsJson = true)]
    public List<Kv> Handlers { get; set; } = new();

    /// <summary>
    /// 上一节点办理时，nextStepCode下拉框中选中的值
    /// config模式：当前节点的difinition.code, dynamic模式：x级部门办理的x：int
    /// </summary>
    public string? PrevChosenStepCode { get; set; }

    /// <summary>
    /// 是否实际办理过该工单
    /// </summary>
    public bool IsActualHandled { get; set; }

    /// <summary>
    /// 节点超期状态
    /// </summary>
    public EExpiredStatus? ExpiredStatus { get; set; }

    /// <summary>
    /// 配置下一步节点 & 谁被选中
    /// </summary>
    [SugarColumn(ColumnDataType = "json", IsJson = true)]
    public List<StepSimple>? NextSteps { get; set; } = new();

    /// <summary>
    /// 前一级节点Id,会签汇总节点无此字段（因可能有多个上级来源）
    /// </summary>
    public string? PrevStepId { get; set; }

    public string? PrevStepCode { get; set; }
    public string? PrevStepName { get; set; }

    /// <summary>
    /// 主办
    /// </summary>
    [SugarColumn(DefaultValue = "f")]
    public bool IsMain { get; set; }

    /// <summary>
    /// 原生节点（区别动态生成）
    /// </summary>
    [SugarColumn(DefaultValue = "f")]
    public bool IsOrigin { get; set; }

    /// <summary>
    /// 节点办理状态
    /// </summary>
    public EWorkflowStepStatus Status { get; set; }

    /// <summary>
    /// 备注
    /// </summary>
    [SugarColumn(ColumnDescription = "备注", ColumnDataType = "varchar(5000)")]
    public string? Remark { get; set; }

    #region 会签

    /// <summary>
    /// 会签id（或外层会签的id）
    /// </summary>
    public string? CountersignId { get; set; }

    /// <summary>
    /// 节点处于会签流程中的位置（区别直接办理会签和会签内非会签节点）
    /// outer属于特殊会签
    /// 最顶层的发起会签节点为none
    /// </summary>
    [SugarColumn(DefaultValue = "0")]
    public ECountersignPosition CountersignPosition { get; set; }

    /// <summary>
    /// 会签直属办理节点(弃用)
    /// </summary>
    [SugarColumn(ColumnDataType = "json", IsJson = true)]
    public List<CountersignStep>? CountersignSteps { get; set; } = new();

    #region 发起会签节点特有

    /// <summary>
    /// 发起会签生成会签Id（不发起会签节点无此字段）
    /// </summary>
    public string? StartCountersignId { get; set; }

    /// <summary>
    /// 发起的会签是否汇总
    /// </summary>
    [SugarColumn(DefaultValue = "f")]
    public bool IsStartedCountersignEnd { get; set; }

    #endregion

    #region 会签汇总节点特有

    /// <summary>
    /// 是否为会签汇总节点
    /// </summary>
    [SugarColumn(DefaultValue = "f")]
    public bool IsCountersignEndStep { get; set; }

    /// <summary>
    /// 开启会签节点id（会签汇总节点对应会签发起节点id）
    /// </summary>
    public string? CountersignStartStepId { get; set; }

    #endregion

    #endregion

    #region 交办

    /// <summary>
    /// 交办人
    /// </summary>
    public string? AssignerId { get; set; }

    public string? AssignerName { get; set; }

    /// <summary>
    /// 交办人部门Id
    /// </summary>
    public string? AssignerOrgId { get; set; }

    public string? AssignerOrgName { get; set; }

    public bool? AssignerOrgIsCenter { get; set; }

    #endregion

    #region 接办

    /// <summary>
    /// 接办人
    /// </summary>
    public string? AcceptorId { get; set; }

    public string? AcceptorName { get; set; }

    /// <summary>
    /// 接办人部门code
    /// </summary>
    public string? AcceptorOrgId { get; set; }

    public string? AcceptorOrgName { get; set; }

    /// <summary>
    /// 接办人部门行政区划代码
    /// </summary>
    public string? AcceptorOrgAreaCode { get; set; }

    /// <summary>
    /// 接办人部门行政区划名称
    /// </summary>
    public string? AcceptorOrgAreaName { get; set; }

    /// <summary>
    /// 接办时间
    /// </summary>
    public DateTime? AcceptTime { get; set; }

    #endregion

    #region 办理

    /// <summary>
    /// 办理人
    /// </summary>
    public string? HandlerId { get; set; }

    public string? HandlerName { get; set; }

    /// <summary>
    /// 办理人部门code
    /// </summary>
    public string? HandlerOrgId { get; set; }

    public bool? HandlerOrgIsCenter { get; set; }

    /// <summary>
    /// 办理人部门名称
    /// </summary>
    public string? HandlerOrgName { get; set; }

    /// <summary>
    /// 办理人部门行政区划代码
    /// </summary>
    public string? HandlerOrgAreaCode { get; set; }

    /// <summary>
    /// 办理人部门行政区划名称
    /// </summary>
    public string? HandlerOrgAreaName { get; set; }

    /// <summary>
    /// 办理完成时间
    /// </summary>
    public DateTime? HandleTime { get; set; }

    /// <summary>
    /// 角色id（如果指派给角色）
    /// </summary>
    public string? RoleId { get; set; }

    public string? RoleName { get; set; }

    /// <summary>
    /// 办理方式
    /// </summary>
    public EHandleMode? HandleMode { get; set; }

    /// <summary>
    /// 审核结果（非审批流程无意义）
    /// </summary>
    [SugarColumn(DefaultValue = "0")]
    public EReviewResult ReviewResult { get; set; }

    #endregion

    #region Definition

    public string Name { get; set; }

    /// <summary>
    /// 模板内唯一
    /// </summary>
    public string Code { get; set; }

    public EStepType StepType { get; init; }

    /// <summary>
    /// 节点业务类型
    /// </summary>
    public EBusinessType BusinessType { get; set; }

    /// <summary>
    /// 办理人类型
    /// </summary>
    public EHandlerType HandlerType { get; set; }

    /// <summary>
    /// 是否有否决按钮
    /// </summary>
    public bool CanReject { get; set; }

    /// <summary>
    /// 执行模式(自动与否)
    /// 只有普通节点支持自动，会签、动态节点均不支持自动
    /// </summary>
    public EExecuteMode ExecuteMode { get; set; }

    #region 会签相关配置

    /// <summary>
    /// 是否支持发起会签（即使支持发起，当下一节点为汇总或结束节点时亦不可发起）
    /// </summary>
    public bool CanStartCountersign { get; set; }

    /// <summary>
    /// 会签策略
    /// </summary>
    public ECountersignPolicy? CountersignPolicy { get; set; }

    #endregion

    #region 依据配置生成节点的方式

    /// <summary>
    /// 实例化模式
    /// </summary>
    public EInstanceMode InstanceMode { get; set; }

    /// <summary>
    /// 动态实例化策略(多次模式才有)
    /// </summary>
    public EDynamicPolicy? InstancePolicy { get; set; }

    /// <summary>
    /// 到此标记终止动态实例化(多次模式才有)
    /// <remarks>
    /// 按直属部门重复既保存orgLevel:int
    /// </remarks>
    /// </summary>
    public string? TerminalDynamicMark { get; set; }

    #endregion

    /// <summary>
    /// 标签
    /// </summary>
    public string? Tag { get; set; }

    #endregion

    #region 办理参数
    #region 办理时赋值

    /// <summary>
    /// (下一节点办理人)根据审批者类型不同，此字段为不同内容
    /// <example>
    /// 部门等级/分类为：orgCodes, 角色为：userIds
    /// </example>
    /// </summary>
    [SugarColumn(ColumnDataType = "json", IsJson = true)]
    public List<StepAssignInfo> NextHandlers { get; set; } = new();

    /// <summary>
    /// 下一节点主办，(NextHandlers其中一个, 如果不是会签则只有一个)
    /// </summary>
    public string? NextMainHandler { get; set; }

    /// <summary>
    /// 下一节点code（stepBox无值）
    /// </summary>
    public string? NextStepCode { get; set; }

    /// <summary>
    /// 是否短信通知
    /// </summary>
    public bool IsSms { get; set; }

    /// <summary>
    /// 办理意见
    /// </summary>
    [SugarColumn(ColumnDataType = "text")]
    public string? Opinion { get; set; }

    /// <summary>
    /// 附件
    /// </summary>
    [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
    public List<FileJson>? FileJson { get; set; }

    /// <summary>
    /// 发起会签
    /// </summary>
    public bool IsStartCountersign { get; set; }

    #endregion
    #region 创建时赋值

    /// <summary>
    /// 节点期满时间
    /// </summary>
    public DateTime? StepExpiredTime { get; set; }

    /// nextStep 信息

    /// <summary>
    /// 是否回到会签发起节点汇总
    /// </summary>
    public bool BackToCountersignEnd { get; set; }

    public EFlowDirection? FlowDirection { get; set; }

    #endregion
    #endregion

    /// <summary>
    /// 老系统Id
    /// </summary>
    [SugarColumn(ColumnDescription = "老系统Id")]
    public string? OldStepId { get; set; }
    
    [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
    public Workflow Workflow { get; set; }

    #region method

    /// <summary>
    /// 开启会签
    /// </summary>
    public void StartCountersign(string startCountersignId)
    {
        IsStartCountersign = true;
        StartCountersignId = startCountersignId;
        IsStartedCountersignEnd = false;
    }

    public bool HasAccepted() => !string.IsNullOrEmpty(AcceptorId);

    public void Accept(
        string userId, string? userName,
        string orgId, string? orgName,
        string? orgAreaCode, string? orgAreaName)
    {
        if (string.IsNullOrEmpty(AcceptorId))
        {
            AcceptorId = userId;
            AcceptorName = userName;
        }

        if (string.IsNullOrEmpty(AcceptorOrgId))
            AcceptorOrgId = orgId;
        if (string.IsNullOrEmpty(AcceptorOrgName))
            AcceptorOrgName = orgName;
        if (string.IsNullOrEmpty(AcceptorOrgAreaCode))
            AcceptorOrgAreaCode = orgAreaCode;
        if (string.IsNullOrEmpty(AcceptorOrgAreaName))
            AcceptorOrgAreaName = orgAreaName;

        AcceptTime = DateTime.Now;
        Status = EWorkflowStepStatus.WaitForHandle;
    }

    public void Handle(
        string userId, string? userName,
        string orgId, string? orgName,
        string? orgAreaCode, string? orgAreaName,
        bool orgIsCenter, EHandleMode handleMode,
        string opinion, string? nextStepCode = null)
    {
        if (!HasAccepted())
            Accept(userId, userName, orgId, orgName, orgAreaCode, orgAreaName);

        Status = EWorkflowStepStatus.Handled;
        if (string.IsNullOrEmpty(HandlerId))
        {
            HandlerId = userId;
            HandlerName = userName;
        }

        if (string.IsNullOrEmpty(HandlerOrgId))
            HandlerOrgId = orgId;
        if (string.IsNullOrEmpty(HandlerOrgName))
            HandlerOrgName = orgName;
        if (string.IsNullOrEmpty(HandlerOrgAreaCode))
            HandlerOrgAreaCode = orgAreaCode;
        if (string.IsNullOrEmpty(HandlerOrgAreaName))
            HandlerOrgAreaName = orgAreaName;
        HandlerOrgIsCenter ??= orgIsCenter;

        HandleTime = DateTime.Now;

        if (!string.IsNullOrEmpty(opinion))
            Opinion = opinion;

        ExpiredStatus = HandleTime > StepExpiredTime
            ? EExpiredStatus.Expired
            : EExpiredStatus.Normal;

        if (!IsInCountersign()
            && InstanceMode is EInstanceMode.Config
            && StepType is not EStepType.End)
        {
            var step = NextSteps.FirstOrDefault(d => d.Code == nextStepCode);
            if (step != null)
                step.Selected = true;
        }

        HandleMode = handleMode;
    }

    /// <summary>
    /// 指派
    /// </summary>
    public void Assign(
        string? handlerId, string? handlerName,
        string? handlerOrgId, string? handlerOrgName,
        string? roleId = null, string? roleName = null)
    {
        HandlerId = handlerId;
        HandlerName = handlerName;
        HandlerOrgId = handlerOrgId;
        HandlerOrgName = handlerOrgName;
        RoleId = roleId;
        RoleName = roleName;
    }

    public void Assign(
        EFlowAssignType flowAssignType,
        string? handlerId, string? handlerName,
        string? handlerOrgId, string? handlerOrgName,
        string? roleId = null, string? roleName = null)
    {
        FlowAssignType = flowAssignType;
        Assign(handlerId, handlerName, handlerOrgId, handlerOrgName, roleId, roleName);
    }

    public void Assign(WorkflowStep step, EFlowAssignType? flowAssignType = null)
    {
        FlowAssignType = flowAssignType ?? step.FlowAssignType;
        HandlerId = step.HandlerId;
        HandlerName = step.HandlerName;
        HandlerOrgId = step.HandlerOrgId;
        HandlerOrgName = step.HandlerOrgName;
        RoleId = step.RoleId;
        RoleName = step.RoleName;
    }

    public void Assign(StepAssignInfo stepAssignInfo)
    {
        FlowAssignType = stepAssignInfo?.FlowAssignType;
        HandlerId = stepAssignInfo?.UserId;
        HandlerName = stepAssignInfo?.Username;
        HandlerOrgId = stepAssignInfo?.OrgId;
        HandlerOrgName = stepAssignInfo?.OrgName;
        RoleId = stepAssignInfo?.RoleId;
        RoleName = stepAssignInfo?.RoleName;
    }

    public void Assign(StepDefine stepDefine)
    {
        var handler = stepDefine.HandlerTypeItems.FirstOrDefault();
        if (handler is null)
            throw new UserFriendlyException($"未正确配置节点办理对象, stepcode: {stepDefine.Code}", "未正确配置节点办理对象");
        switch (stepDefine.HandlerType)
        {
            case EHandlerType.Role:
                FlowAssignType = EFlowAssignType.Role;
                RoleId = handler.Key;
                RoleName = handler.Value;
                break;
            case EHandlerType.AssignedUser:
                FlowAssignType = EFlowAssignType.User;
                HandlerId = handler.Key;
                HandlerName = handler.Value;
                break;
            case EHandlerType.AssignedOrg:
                FlowAssignType = EFlowAssignType.Org;
                HandlerOrgId = handler.Key;
                HandlerOrgName = handler.Value;
                break;
            case EHandlerType.OrgType:
                throw new ArgumentOutOfRangeException("部门类型不支持按配置指派");
            case EHandlerType.OrgLevel:
                throw new ArgumentOutOfRangeException("部门等级不支持按配置指派");
            default:
                throw new ArgumentOutOfRangeException();
        }

    }

    /// <summary>
    /// 是否处于会签流程中(不包含顶层发起会签节点)
    /// </summary>
    public bool IsInCountersign() => CountersignPosition != ECountersignPosition.None;

    public Kv GetHandler()
    {
        return FlowAssignType switch
        {
            EFlowAssignType.Org => new Kv(HandlerOrgId, HandlerOrgName),
            EFlowAssignType.User => new Kv(HandlerId, HandlerName),
            EFlowAssignType.Role => new Kv(RoleId, RoleName),
            EFlowAssignType.OrgAndRole => new Kv(RoleId, $"{HandlerOrgName} - {RoleName}"),
            _ => throw new ArgumentOutOfRangeException()
        };
    }

    public StepAssignInfo GetWorkflowStepHandler()
    {
        switch (FlowAssignType)
        {
            case EFlowAssignType.Org:
            case EFlowAssignType.OrgAndRole:
                return new StepAssignInfo
                {
                    FlowAssignType = FlowAssignType.Value,
                    Key = HandlerOrgId,
                    Value = HandlerOrgName,
                    //UserId = HandlerId,
                    //Username = HandlerName,
                    OrgId = HandlerOrgId,
                    OrgName = HandlerOrgName,
                    RoleId = RoleId,
                    RoleName = RoleName,
                };
            case EFlowAssignType.User:
                return new StepAssignInfo
                {
                    FlowAssignType = FlowAssignType.Value,
                    Key = HandlerId,
                    Value = HandlerName,
                    UserId = HandlerId,
                    Username = HandlerName,
                    OrgId = HandlerOrgId,
                    OrgName = HandlerOrgName,
                    RoleId = RoleId,
                    RoleName = RoleName
                };
            case EFlowAssignType.Role:
                return new StepAssignInfo
                {
                    FlowAssignType = FlowAssignType.Value,
                    Key = RoleId,
                    Value = RoleName,
                    UserId = HandlerId,
                    Username = HandlerName,
                    OrgId = HandlerOrgId,
                    OrgName = HandlerOrgName,
                    RoleId = RoleId,
                    RoleName = RoleName
                };
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

	#endregion
}

/*
feature: 
1. step增加字段记录roleId, roleName
2. 指派时为对应办理对象赋值，办理时为所有办理对象字段赋值
3. 配置办理对象为角色时，如果未指定办理人则指派给角色办理
4. thk从默认派单池中分配给对应办理人时指定办理对象
refactor:
1. step增加字段记录发起会签或是或签
2. status增加或签无需办理状态
3. 办理节点时判断是否立即结束会签或者等全部节点办完再结束
 */