using System.Text;
using Infrastructure;
using OpenAuth.App.Base;
using OpenAuth.App.BaseApp.Base;
using OpenAuth.App.Interface;
using OpenAuth.App.Permission.Request;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using SqlSugar;

namespace OpenAuth.App.Permission;

/// <summary>
/// 数据权限业务类
/// </summary>
public class BaseDataAuthorizeApp : SqlSugarBaseApp<BaseDataAuth, SugarDbContext>
{
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="unitWork"></param>
    /// <param name="repository"></param>
    /// <param name="auth"></param>
    public BaseDataAuthorizeApp(ISugarUnitOfWork<SugarDbContext> unitWork, ISimpleClient<BaseDataAuth> repository,
        IAuth auth) : base(unitWork, repository, auth)
    {
    }


    #region 获取数据

    /// <summary>
    /// 获取数据权限对应关系数据列表
    /// </summary>
    /// <param name="code">编码</param>
    /// <param name="objectIds">用户或角色主键</param>
    /// <returns></returns>
    public Task<List<BaseDataAuth>> GetList(string code, string[] objectIds)
    {
        return Repository.AsQueryable()
            .Where(t => t.Code.Equals(code)
                        && (objectIds.Contains(t.ObjectId) || t.ObjectType == 3)
            ).ToListAsync();
    }

    /// <summary>
    /// 获取数据权限列表（分页）
    /// </summary>
    public async Task<Response<PageInfo<List<BaseDataAuth>>>> GetPageList(BaseDataAuthListReq req)
    {
        RefAsync<int> totalCount = 0;
        // 实现查询及分页
        var result = await Repository.AsQueryable()
            .WhereIF(req.Type != null, t => t.Type == req.Type)
            .WhereIF(!string.IsNullOrEmpty(req.ObjectId), t => t.ObjectId == req.ObjectId)
            .WhereIF(!string.IsNullOrEmpty(req.key), t => t.Name.Contains(req.key) || t.Code.Contains(req.key))
            .ToPageListAsync(req.page, req.limit, totalCount);

        return new Response<PageInfo<List<BaseDataAuth>>>
        {
            Result = new PageInfo<List<BaseDataAuth>>
            {
                Items = result,
                Total = totalCount
            }
        };
    }

    /// <summary>
    /// 获取实体
    /// </summary>
    /// <param name="keyValue">主键</param>
    /// <returns></returns>
    public Task<BaseDataAuth> GetEntity(string keyValue)
    {
        return Repository.GetByIdAsync(keyValue);
    }

    #endregion

    #region 提交数据

    /// <summary>
    /// 删除实体数据
    /// </summary>
    /// <param name="keyValue">主键</param>
    /// <returns></returns>
    public async Task DeleteEntity(string keyValue)
    {
        await Repository.DeleteByIdAsync(keyValue);
    }

    /// <summary>
    /// 保存实体数据（新增、修改）
    /// </summary>
    /// <param name="keyValue">主键</param>
    /// <param name="entity">实体</param>
    /// <returns></returns>
    public async Task SaveEntity(string keyValue, BaseDataAuthReq record)
    {
        var user = _auth.GetCurrentUser();
        var entity = record.MapTo<BaseDataAuth>();
        entity.Formula = record.Formula.ToJson();
        if (string.IsNullOrEmpty(keyValue))
        {
            entity.Id = Guid.NewGuid().ToString();
            entity.CreateDate = DateTime.Now;
            entity.CreateUserId = user.User.Id.ToString();
            entity.CreateUserName = user.User.Name;
        }
        else
        {
            entity.Id = keyValue;
            entity.ModifyDate = DateTime.Now;
            entity.ModifyUserId = user.User.Id.ToString();
            entity.ModifyUserName = user.User.Name;
        }
        // 全部值都更新了
        await Repository.InsertOrUpdateAsync(entity);
    }

    #endregion

    #region 扩展方法

    /// <summary>
    /// 获取自定义表单数据权限查询条件
    /// </summary>
    /// <param name="code">自定义表单功能主键</param>
    /// <returns></returns>
    /// todo 可以优化，使代码逻辑清晰，减少代码量，比如有无公式，可以合并部分逻辑
    /// 逻辑：1. 超级用户不做过滤 2. 先看有无公式（默认条件使用and连接），再看有无分组公式（分组公式使用and连接）
    public async Task<string> GetWhereSql(string code)
    {
        // 取得当前用户信息
        var userInfo = _auth.GetCurrentUser();
        // 超级用户不做过滤 todo 暂时注释
        /*if (userInfo.User.Id.Equals(-1))
        {
            return "";
        }*/

        // 26个字母干嘛用的？别名？
        var numIndex = new[]
        {
            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
            "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
        };

        // 获取数据权限配置信息
        // 查询当前用户所拥有的角色或者岗位
        var roleIds = userInfo.Roles.Select(t => t.Id).MapToList<string>();
        var objectIds = new List<string> { userInfo.User.Id + "", };
        objectIds.AddRange(roleIds);
        // code  自定义表单功能主键  查询当前用户或者用户所属角色是否有设置的权限规则
        var baseDataAuths = await GetList(code, objectIds.ToArray());

        // 保存拼接的sql
        var whereSqlSb = new StringBuilder();
        var sqlNum = 0;
        foreach (var auth in baseDataAuths)
        {
            //{"formula":"A and B",
            //"conditions":[
            //{"f_FieldId":"F_text0","f_Symbol":1,"f_FieldValueType":1,"f_FieldValue":"xxx","group":"","type":"","table":"","cfield":"","field":"","relationField":""}],
            //"formulas":[1 or 2]}
            // 判断是否是开头
            // 先运行这里
            // 不同数据权限规则使用or ，很可能只有一条吧
            whereSqlSb.Append(sqlNum > 0 ? " AND ( " : " ( ");
            var strSql = "";
            // 反序列化数据权限公式
            var itemFormula = auth.Formula.ToObject<FormulaObject>();
            // formula 不存在时，直接使用and连接
            if (string.IsNullOrEmpty(itemFormula.Formula))
            {
                // Conditions 
                // 默认公式
                for (var i = 1; i < itemFormula.Conditions.Count + 1; i++)
                {
                    var conditionItem = itemFormula.Conditions[i - 1];
                    conditionItem.index = i; // 赋值索引，后面应该会用到，从1开始
                    // 这里的Group是字符串，大概是字母 A B 之类 ，如何没有Group，条件之间用 and 连接
                    if (!string.IsNullOrEmpty(conditionItem.Group))
                    {
                        continue;
                    }

                    if (strSql != "")
                    {
                        strSql += " AND ";
                    }

                    strSql += " {@hopetry" + i + "hopetry@} ";
                }

                // 公式为空，分组公式不为空
                if (itemFormula.Formulas != null && itemFormula.Formulas.Count > 0)
                {
                    // 假设分组公式只有1个 【{“value”: "1 or 2"}】 多个分组公式之间，使用and连接
                    for (var i = 0; i < itemFormula.Formulas.Count; i++)
                    {
                        if (itemFormula.Conditions.FindIndex(t => t.Group == numIndex[i]) != -1)
                        {
                            if (strSql != "")
                            {
                                strSql += " AND ";
                            }

                            strSql += " {@hopetry" + numIndex[i] + "hopetry@} ";
                        }
                    }
                }
            }
            // 存在公式
            else
            {
                // 当分组公式存在时，公式含有分组信息，如： A and B
                strSql = itemFormula.Formula;
                // 为什么从1开头
                for (var i = 1; i < itemFormula.Conditions.Count + 1; i++)
                {
                    var conditionItem = itemFormula.Conditions[i - 1];
                    // 取了条件没有使用
                    conditionItem.index = i;
                    strSql = strSql.Replace("" + i, "{@hopetry" + i + "hopetry@}");
                }

                if (itemFormula.Formulas != null && itemFormula.Formulas.Count > 0)
                {
                    for (var i = 0; i < itemFormula.Formulas.Count; i++)
                    {
                        strSql = strSql.Replace(numIndex[i], "{@hopetry" + numIndex[i] + "hopetry@}");
                    }
                }
            }

            // 针对公组公式存在，再做部分处理，todo 暂时可以忽略，不实现分组
            if (itemFormula.Formulas != null && itemFormula.Formulas.Count > 0)
            {
                // 分组公式
                for (var i = 0; i < itemFormula.Formulas.Count; i++)
                {
                    var groupSql = new StringBuilder();
                    var groupList = itemFormula.Conditions.FindAll(t => t.Group == numIndex[i]);
                    if (groupList.Count > 0)
                    {
                        groupSql.Append(
                            // relationField 关联字段（外键）  这里的Table应该是子表吧
                            $" {groupList[0].RelationField} in ( SELECT {groupList[0].Field} FROM {groupList[0].Table} WHERE ");

                        // 初始化分组公式
                        var groupSqlWhere = "";
                        if (string.IsNullOrEmpty(itemFormula.Formulas[i].Value))
                        {
                            foreach (var groupItem in groupList)
                            {
                                if (groupSqlWhere != "")
                                {
                                    groupSqlWhere += " AND ";
                                }

                                groupSqlWhere += " {@hopetry" + groupItem.index + "hopetry@} ";
                            }
                        }
                        else
                        {
                            groupSqlWhere = itemFormula.Formulas[i].Value;
                            foreach (var groupItem in groupList)
                            {
                                groupSqlWhere = groupSqlWhere.Replace("" + groupItem.index,
                                    "{@hopetry" + groupItem.index + "hopetry@}");
                            }
                        }

                        foreach (var groupItem in groupList)
                        {
                            var strone = new StringBuilder();
                            if (groupItem.F_Symbol.Equals("8"))
                            {
                                strone.Append($" ({groupItem.Cfield} ");
                            }
                            else
                            {
                                strone.Append($" {groupItem.Cfield} ");
                            }

                            var value = await GetValue(int.Parse(groupItem.F_FieldValueType), groupItem.F_FieldValue);
                            switch (int.Parse(groupItem.F_Symbol))
                            {
                                case 1: // 等于
                                    strone.Append($" = {value}");
                                    break;
                                case 2: // 大于
                                    strone.Append($" > {value}");
                                    break;
                                case 3: // 大于等于
                                    strone.Append($" >= {value}");
                                    break;
                                case 4: // 小于
                                    strone.Append($" < {value}");
                                    break;
                                case 5: // 小于等于
                                    strone.Append($" <= {value}");
                                    break;
                                case 6: // 包含
                                    value = value.Replace("'", "");
                                    strone.Append($" like '%{value}%'");
                                    break;
                                case 7: // 包含于
                                    value = value.Replace(",", "','");
                                    strone.Append($" in ({value})");
                                    break;
                                case 8: // 不等于
                                    strone.Append($" != {value} or {groupItem.Cfield} is null ) ");
                                    break;
                                case 9: // 不包含
                                    value = value.Replace("'", "");
                                    strone.Append($" not like '%{value}%'");
                                    break;
                                case 10: // 不包含于
                                    value = value.Replace(",", "','");
                                    strone.Append($" not in ({value})");
                                    break;
                                default:
                                    break;
                            }

                            groupSqlWhere = groupSqlWhere.Replace("{@hopetry" + groupItem.index + "hopetry@}",
                                strone.ToString());
                        }

                        groupSql.Append(groupSqlWhere);
                        groupSql.Append(" ) ");
                        strSql = strSql.Replace("{@hopetry" + numIndex[i] + "hopetry@}", groupSql.ToString());
                    }
                }
            }

            // 填充占位符，生成实际wheresql
            var num = 1;
            foreach (var conditionItem in itemFormula.Conditions)
            {
                // 这里的group应该是 A B C 之类的字母
                if (string.IsNullOrEmpty(conditionItem.Group))
                {
                    var strone = new StringBuilder();
                    if (conditionItem.Type == "glbd") // 未使用
                    {
                        strone.Append(
                            $" {conditionItem.RelationField} in ( SELECT {conditionItem.Field} FROM {conditionItem.Table} WHERE {conditionItem.Cfield}  ");
                    }
                    else
                    {
                        // 8 不等于
                        if (conditionItem.F_Symbol.Equals("8"))
                        {
                            strone.Append($" ( {conditionItem.F_FieldId}");
                        }
                        else
                        {
                            strone.Append($" {conditionItem.F_FieldId}");
                        }
                    }

                    var value = await GetValue(int.Parse(conditionItem.F_FieldValueType), conditionItem.F_FieldValue);
                    // 如果 value 值是 userId 
                    switch (int.Parse(conditionItem.F_Symbol))
                    {
                        case 1: // 等于
                            strone.Append($" = {value}");
                            break;
                        case 2: // 大于
                            strone.Append($" > {value}");
                            break;
                        case 3: // 大于等于
                            strone.Append($" >= {value}");
                            break;
                        case 4: // 小于
                            strone.Append($" < {value}");
                            break;
                        case 5: // 小于等于
                            strone.Append($" <= {value}");
                            break;
                        case 6: // 包含
                            value = value.Replace("'", "");
                            strone.Append($" like '%{value}%'");
                            break;
                        case 7: // 包含于
                            value = value.Replace(",", "','");
                            value = value.Replace("#", ",");
                            strone.Append($" in ({value})");
                            break;
                        case 8: // 不等于
                            strone.Append($" != {value}");

                            if (conditionItem.Type == "glbd")
                            {
                                strone.Append($" or {conditionItem.Cfield} is null  ");
                            }
                            else
                            {
                                strone.Append($" or {conditionItem.F_FieldId} is null ) ");
                            }

                            break;
                        case 9: // 不包含
                            value = value.Replace("'", "");
                            strone.Append($" not like '%{value}%'");
                            break;
                        case 10: // 不包含于
                            value = value.Replace(",", "','");
                            strone.Append($" not in ({value})");
                            break;
                        default:
                            break;
                    }

                    strone.Append(conditionItem.Type == "glbd" ? " ) " : " ");
                    strSql = strSql.Replace("{@hopetry" + num + "hopetry@}", strone.ToString());
                }

                num++;
            }

            whereSqlSb.Append(strSql);
            whereSqlSb.Append(" ) ");

            sqlNum++;
        }

        Console.WriteLine("strRes:" + whereSqlSb.ToString());
        return whereSqlSb.ToString();
    }

    /// <summary>
    /// 获取数据 where 值部分
    /// </summary>
    /// <param name="type">数据类型</param>
    /// <param name="value">数据值</param>
    /// <returns></returns>
    /// 

    // todo  扩展改造
    private async Task<string> GetValue(int? type, string value)
    {
        var userInfo = _auth.GetCurrentUser();
        //1.文本(string) 2.登录者ID 3.登录者账号  4.登录者部门  5. 登录者部门及下属部门 6.登录者岗位 7.登录者角色 10. 文本（int）
        string text;
        switch (type)
        {
            case 1: // 文本(string)
                text = $"'{value}'";
                break;
            case 10: // 文本（int）
                text = value;
                break;
            case 2: // 登录者ID(本地创建数据)
                text = userInfo.User.Id +　"";
                break;
            case 3: // 登录者账号
                text = $"'{userInfo.User.Account}'";
                break;
            // todo  扩展实现
            case 4: // 本部门
                text =
                    $"( SELECT CAST ( \"OrgId\" AS VARCHAR ) AS \"OrgId\" FROM sys_userorg WHERE \"UserId\" = '{userInfo.User.Id}' )";
                break;
            case 5: // 本部门及子部门
                text =
                    $"select CAST(\"Id\" AS VARCHAR) from sys_org where string_to_array(\"CascadeId\"#'.')  && ARRAY['{string.Join(",", userInfo.Orgs.Select(t => t.Id).MapToList<string>())}']";
                break;
            case 6:
                text = "";
                break;
            case 7:
                text = $"'{string.Join(",", userInfo.Roles.Select(t => t.Id).MapToList<string>())}'";
                break;
            default:
                text = $"'{value}'";
                break;
        }

        return text;
    }

    #endregion

    public async Task<Response<Repository.Domain.FormScheme>> GetEntityByCode(string code)
    {
        var formModuleEntity = await Repository
            .ChangeRepository<SugarRepositiry<FormModuleEntity>>()
            .GetFirstAsync(r => r.Id == code);
        if (formModuleEntity != null)
        {
            var formScheme = await base.Repository.ChangeRepository<SugarRepositiry<Repository.Domain.FormScheme>>()
                .GetFirstAsync(r => r.Id == formModuleEntity.FormVerison);
            return new Response<Repository.Domain.FormScheme>()
            {
                Result = formScheme,
                Message = "查询成功"
            };
        }

        throw new Exception("code无效");
    }
}