using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;

namespace NPin.Framework.Ddd.Application;

public abstract class
    NPinCrudAppService<TEntity, TEntityDto, TKey> : NPinCrudAppService<TEntity, TEntityDto, TKey,
    PagedAndSortedResultRequestDto>
    where TEntity : class, IEntity<TKey>
    where TEntityDto : IEntityDto<TKey>
{
    protected NPinCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
    {
    }
}

public abstract class NPinCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>
    : NPinCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto>
    where TEntity : class, IEntity<TKey>
    where TEntityDto : IEntityDto<TKey>
{
    protected NPinCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
    {
    }
}

public abstract class NPinCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>
    : NPinCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
    where TEntity : class, IEntity<TKey>
    where TEntityDto : IEntityDto<TKey>
{
    protected NPinCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
    {
    }
}

public abstract class NPinCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
    : NPinCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
    where TEntity : class, IEntity<TKey>
    where TEntityDto : IEntityDto<TKey>
{
    protected NPinCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
    {
    }
}

public abstract class NPinCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput,
    TUpdateInput> :
    CrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
    where TEntity : class, IEntity<TKey>
    where TGetOutputDto : IEntityDto<TKey>
    where TGetListOutputDto : IEntityDto<TKey>
{
    protected NPinCrudAppService(IRepository<TEntity, TKey> repository) : base(repository)
    {
    }

    /// <summary>
    /// 多查/批量查
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public override async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
    {
        List<TEntity> entities;
        // 区分查/批量查
        if (input is IPagedResultRequest pagedInput)
        {
            entities = await Repository.GetPagedListAsync(pagedInput.SkipCount, pagedInput.MaxResultCount,
                string.Empty);
        }
        else
        {
            entities = await Repository.GetListAsync();
        }

        var total = await Repository.GetCountAsync();
        var output = await MapToGetListOutputDtosAsync(entities);
        return new PagedResultDto<TGetListOutputDto>(total, output);
    }

    /// <summary>
    /// 多删
    /// </summary>
    /// <param name="ids"></param>
    [RemoteService(isEnabled: true)]
    public virtual async Task DeleteAsync(IEnumerable<TKey> ids)
    {
        await Repository.DeleteManyAsync(ids);
    }

    /// <summary>
    /// 单删（覆盖）
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [RemoteService(isEnabled: false)]
    public override Task DeleteAsync(TKey id)
    {
        return base.DeleteAsync(id);
    }

    /// <summary>
    /// 导出Excel
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public virtual async Task<IActionResult> GetExportExcelAsync(TGetListInput input)
    {
        if (input is IPagedResultRequest paged)
        {
            // 不进行分页
            paged.SkipCount = 0;
            paged.MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount;
        }

        var output = await this.GetListAsync(input);
        var dirPath = $"/temp";

        var filename = $"{typeof(TEntity).Name}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{Guid.NewGuid()}";
        var filePath = $"{dirPath}/{filename}.xlsx";
        if (!Directory.Exists(dirPath))
        {
            Directory.CreateDirectory(dirPath);
        }

        await MiniExcel.SaveAsAsync(filePath, output.Items);
        return new PhysicalFileResult(filePath, "application/vnd.ms-excel");
    }

    /// <summary>
    /// 导入Excel
    /// </summary>
    /// <param name="input"></param>
    public virtual async Task PostImportExcelAsync(List<TCreateInput> input)
    {
        // var entities = input.Select(MapToEntity).ToList();
        // await Repository.InsertManyAsync(entities);
        
        // 需子类自行实现
        throw new NotImplementedException();
    }
}