using System.Reflection;

namespace Tiobon.Core.Controllers;

/// <summary>
/// 增删改查基础服务
/// </summary>
/// <typeparam name="IServiceBase"></typeparam>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TEntityDto"></typeparam>
/// <typeparam name="TInsertDto"></typeparam>
/// <typeparam name="TEditDto"></typeparam>
public class BaseController<IServiceBase, TEntity, TEntityDto, TInsertDto, TEditDto> : Controller
{
    #region 初始化
    protected IServiceBase _service;
    /// <summary>
    /// 初始化 (注入)
    /// </summary>
    public BaseController(IServiceBase service)
    {
        _service = service;
    }
    #endregion


    #region 基础接口

    #region 查询
    /// <summary>
    /// 根据条件查询数据
    /// </summary>
    /// <param name="body">条件</param>
    /// <returns></returns>
    [HttpPost, Route("Query")]
    public virtual async Task<ServicePageResult<TEntityDto>> QueryByFilter([FromBody] QueryBody body)
    {
        var data = (await InvokeServiceAsync("QueryFilterPage", [body])) as ServicePageResult<TEntityDto>;
        return data;
    }

    public static T ConvertTo<T>(object input)
    {
        if (input == null)
        {
            throw new ArgumentNullException(nameof(input));
        }

        // 当T是Nullable类型时，需要获取其基础类型
        Type targetType = typeof(T);
        Type nullableType = Nullable.GetUnderlyingType(targetType);
        targetType = nullableType ?? targetType;

        // 检查input是否已经是T类型
        if (input is T)
        {
            return (T)input;
        }

        // 尝试转换
        try
        {
            return (T)Convert.ChangeType(input, targetType);
        }
        catch (InvalidCastException)
        {
            throw new InvalidOperationException($"Cannot convert an instance of type {input.GetType().Name} to type {typeof(T).Name}.");
        }
    }

    /// <summary>
    ///  根据Id查询数据
    /// </summary>
    /// <param name="Id">主键ID</param>
    /// <returns></returns>
    [HttpPost("Query/{Id}")]
    public virtual async Task<ServiceResult<TEntityDto>> QueryById(long Id)
    {
        var entity1 = await InvokeServiceAsync("QueryById", [Id]);
        var entity = ConvertTo<TEntityDto>(entity1);
        if (entity is null)
            return Failed<TEntityDto>("获取失败");
        else
            return Success<TEntityDto>(entity, "获取成功");
    }
    /// <summary>
    ///  查询菜单表单信息
    /// </summary>
    /// <param name="body">body</param>
    /// <returns></returns>
    [HttpPost("QueryForm")]
    public virtual async Task<ServiceFormResult> QueryForm([FromBody] QueryForm body)
    {
        var entity = await InvokeServiceAsync("QueryForm", [body]) as ServiceFormResult;
        return entity;
    }
    #endregion

    #region 新增
    /// <summary>
    /// 新增数据
    /// </summary>
    /// <param name="insertModel"></param>
    /// <returns></returns>
    [HttpPost("Insert")]
    public virtual async Task<ServiceResult<string>> Insert([FromBody] TInsertDto insertModel)
    {
        var data = Success<string>(null, "新增成功");
        var id = Convert.ToInt64(await InvokeServiceAsync("Add", [insertModel]));
        data.Success = id > 0;
        if (data.Success)
            data.Data = id.ObjToString();
        else
            return Failed<string>("新增失败");

        return data;
    }

    /// <summary>
    /// 批量新增数据
    /// </summary>
    /// <param name="insertModels"></param>
    [HttpPost, Route("BulkInsert")]
    public virtual async Task<ServiceResult<List<long>>> BulkInsert([FromBody] List<TInsertDto> insertModels)
    {
        var data = Success<List<long>>(null, "新增成功");
        var ids = await InvokeServiceAsync("Add", [insertModels]) as List<long>;
        data.Success = ids.Any();
        if (data.Success)
            data.Data = ids;
        else
            return Failed<List<long>>("新增失败");

        return data;
    }

    #endregion

    #region 更新
    /// <summary>
    /// 更新数据
    /// </summary>
    /// <param name="Id">主键ID</param>
    /// <param name="editModel"></param>
    /// <returns></returns>
    [HttpPost("Update/{Id}")]
    public virtual async Task<ServiceResult> Put(long Id, [FromBody] TEditDto editModel)
    {
        var data = Success("更新成功");
        var flag = Convert.ToBoolean(await InvokeServiceAsync("Update", [Id, editModel]));
        if (!flag)
            return Failed("更新失败");
        return data;
    }
    /// <summary>
    ///  批量更新数据
    /// </summary>
    /// <param name="editModels"></param>
    [HttpPost, Route("BulkUpdate")]
    public virtual async Task<ServiceResult> BulkUpdate([FromBody] Dictionary<long, TEditDto> editModels)
    {
        var data = Success("更新成功");
        var flag = Convert.ToBoolean(await InvokeServiceAsync("Update", [editModels]));
        if (!flag)
            return Failed("更新失败");
        return data;
    }
    #endregion

    #region 删除
    /// <summary>
    /// 删除数据
    /// </summary>
    /// <param name="Id">主键ID</param>
    /// <returns></returns>
    [HttpPost("Delete/{Id}")]
    public virtual async Task<ServiceResult> Delete(long Id)
    {
        var data = Success("删除成功");
        var isExist = Convert.ToBoolean(await InvokeServiceAsync("AnyAsync", [Id]));
        if (!isExist)
            return Failed("删除失败");
        data.Success = Convert.ToBoolean(await InvokeServiceAsync("DeleteById1", [Id]));
        if (!data.Success)
            return Failed("删除失败");
        return data;
    }

    /// <summary>
    /// 批量删除数据
    /// </summary>
    /// <param name="Ids">主键IDs</param>
    /// <returns></returns>
    [HttpPost, Route("BulkDelete")]
    public virtual async Task<ServiceResult> BulkDelete([FromBody] long[] Ids)
    {
        var data = Success("删除成功");
        data.Success = Convert.ToBoolean(await InvokeServiceAsync("DeleteByIds1", [Ids]));
        if (!data.Success)
            return Failed("删除失败");
        return data;
    }
    #endregion

    #endregion

    #region Excel导出
    /// <summary>
    /// Excel导出
    /// </summary>
    /// <param name="body"></param>
    /// <returns></returns>
    [HttpPost, Route("Export")]
    public async Task<ServiceResult<long>> Export([FromBody] QueryBody body)
    {
        var data = (await InvokeServiceAsync("Export", [body])) as ServiceResult<long>;
        return data;
    }
    #endregion

    ///// <summary>
    ///// 反射调用service方法
    ///// </summary>
    ///// <param name="methodName"></param>
    ///// <param name="parameters"></param>
    ///// <returns></returns>
    //[NonAction]
    //private object InvokeService(string methodName, object[] parameters)
    //{
    //    return _service.GetType().GetMethod(methodName).Invoke(_service, parameters);
    //}
    ///// <summary>
    ///// 反射调用service方法
    ///// </summary>
    ///// <param name="methodName"></param>
    ///// <param name="types">为要调用重载的方法参数类型：new Type[] { typeof(SaveDataModel)</param>
    ///// <param name="parameters"></param>
    ///// <returns></returns>
    //[NonAction]
    //private object InvokeService(string methodName, Type[] types, object[] parameters) => _service.GetType().GetMethod(methodName, types).Invoke(_service, parameters);


    [NonAction]
    private async Task<object> InvokeServiceAsync(string methodName, object[] parameters)
    {
        var task = _service.GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, null, _service, parameters) as Task;
        if (task != null) await task;
        var result = task?.GetType().GetProperty("Result")?.GetValue(task);
        return result;
    }

    [NonAction]
    public ServiceResult<T> Success<T>(T data, string message = "成功")
    {
        return new ServiceResult<T>() { Success = true, Message = message, Data = data, };
    }

    // [NonAction]
    //public ServiceResult<T> Success<T>(T data, string msg = "成功",bool success = true)
    //{
    //    return new ServiceResult<T>()
    //    {
    //        success = success,
    //        msg = msg,
    //        response = data,
    //    };
    //}
    [NonAction]
    public ServiceResult Success(string message = "成功")
    {
        return new ServiceResult() { Success = true, Message = message, Data = null, };
    }

    [NonAction]
    public ServiceResult Failed(string message = "失败", int status = 500)
    {
        return new ServiceResult() { Success = false, Status = status, Message = message, Data = null, };
    }

    [NonAction]
    public ServiceResult<T> Failed<T>(string message = "失败", int status = 500)
    {
        return new ServiceResult<T>() { Success = false, Status = status, Message = message, Data = default, };
    }

    //Mapper.Map(data).ToANew<TEntityDto>()

    [NonAction]
    public ServiceResult<PageModel<T>> SuccessPage<T>(int page, int dataCount, int pageSize, List<T> data, int pageCount, string message = "获取成功")
    {
        return new ServiceResult<PageModel<T>>() { Success = true, Message = message, Data = new PageModel<T>(page, dataCount, pageSize, data) };
    }

    [NonAction]
    public ServiceResult<PageModel<T>> SuccessPage<T>(PageModel<T> pageModel, string message = "获取成功")
    {
        return new ServiceResult<PageModel<T>>() { Success = true, Message = message, Data = pageModel };
    }
}