using Furion.DatabaseAccessor.Extensions;
using YBEE.EQM.Core;

namespace YBEE.EQM.Application;

/// <summary>
/// 学校班级信息管理服务
/// </summary>
public class SchoolClassService : ISchoolClassService, ITransient
{
    private readonly IRepository<SchoolClass> _rep;
    public SchoolClassService(IRepository<SchoolClass> rep)
    {
        _rep = rep;
    }

    /// <summary>
    /// 添加学校班级
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task Add(AddSchoolClassInput input)
    {
        if (!CurrentSysUserInfo.IsSuperAdmin)
        {
            input.SysOrgId = CurrentSysUserInfo.SysOrgId;
        }
        var check = await _rep.AnyAsync(t => t.SysOrgId == input.SysOrgId && t.EducationStage == input.EducationStage && t.GradeBeginYear == input.GradeBeginYear && t.ClassNumber == input.ClassNumber);
        if (check)
        {
            throw Oops.Oh(ErrorCode.E2003, "在同年级中", "班级号");
        }
        var item = input.Adapt<SchoolClass>();
        await item.InsertAsync();
    }
    /// <summary>
    /// 批量添加学校班级
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task BatchAdd(BatchAddSchoolClassInput input)
    {
        if (!CurrentSysUserInfo.IsSuperAdmin)
        {
            input.SysOrgId = CurrentSysUserInfo.SysOrgId;
        }
        var maxClass = await _rep.Where(t => t.SysOrgId == input.SysOrgId && t.EducationStage == input.EducationStage && t.GradeBeginYear == input.GradeBeginYear).OrderByDescending(t => t.ClassNumber).FirstOrDefaultAsync();
        List<SchoolClass> newClass = new();
        for (short i = maxClass?.ClassNumber ?? 0; i < input.ClassCount;)
        {
            i++;
            var nc = input.Adapt<SchoolClass>();
            nc.Id = GetSchoolClassId(input.EducationStage, input.SysOrgId, input.GradeBeginYear, i);
            nc.ClassNumber = i;
            SetSchoolClassName(nc, input.EducationStage, input.GradeBeginYear, i);
            newClass.Add(nc);
        }
    }
    /// <summary>
    /// 获取批量导入班级ID
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<Dictionary<short, long>> GetImportSchoolClassList(ImportSchoolClassInput input)
    {
        var scs = await _rep.DetachedEntities.Where(t => t.SysOrgId == input.SysOrgId && t.EducationStage == input.ExamGrade.EducationStage && t.GradeBeginYear == input.ExamGrade.GradeBeginYear).ToListAsync();

        // 不存在的班级
        var newClassNumbers = (from c in input.ClassNumberList
                               where !(from s in scs select s.ClassNumber).Contains(c)
                               select c).ToList();
        // 已存在的班级
        Dictionary<short, long> ret = (from s in scs
                                       where input.ClassNumberList.Contains(s.ClassNumber)
                                       select s).ToDictionary(x => x.ClassNumber, y => y.Id);

        ret ??= new Dictionary<short, long>();

        // 添加不存在的班级
        List<SchoolClass> newClasses = new();
        foreach (var c in newClassNumbers)
        {
            long id = GetSchoolClassId(input.ExamGrade.EducationStage, input.SysOrgId, input.ExamGrade.GradeBeginYear, c);
            ret.Add(c, id);
            SchoolClass newItem = new()
            {
                Id = id,
                ClassNumber = c,
                SysOrgId = input.SysOrgId,
                SysOrgBranchId = input.SysOrgBranchId,
                EducationStage = input.ExamGrade.EducationStage,
                EducationYears = input.ExamGrade.EducationYears,
                GradeBeginYear = input.ExamGrade.GradeBeginYear,
                GradeEndYear = input.ExamGrade.GradeEndYear,
            };
            SetSchoolClassName(newItem, input.ExamGrade.EducationStage, input.ExamGrade.GradeBeginYear, c);
            newClasses.Add(newItem);
        }
        if (newClasses.Any())
        {
            await _rep.InsertNowAsync(newClasses);
        }

        return ret;
    }
    /// <summary>
    /// 批量插入班级
    /// </summary>
    /// <param name="schoolClasses"></param>
    /// <returns></returns>
    public async Task BatchInsert(List<BatchInsertSchoolClassInput> schoolClasses)
    {
        if(!schoolClasses.Any())
        {
            return;
        }
        var selectSqls = schoolClasses.Select(t =>
        {
            string sobid = "NULL";
            if (t.SysOrgBranchId.HasValue)
            {
                sobid = t.SysOrgBranchId.ToString();
            }
            string fullName = BuildFullName(t.EducationStage, t.GradeBeginYear, t.ClassNumber);
            string name = BuildName(t.GradeBeginYear, t.ClassNumber);
            string shortName = BuildShortName(t.ClassNumber);
            return @$"
    SELECT {t.Id} AS id, {t.SysOrgId} soid, {sobid} sobid, {(short)t.EducationYears} es, {t.ClassNumber} cn, '{name}' n, '{fullName}' fn, '{shortName}' sn, {t.GradeBeginYear} gby, {t.GradeEndYear} gey, {t.EducationYears} ey ";
        });

        string selectUnionAll = string.Join("UNION ALL", selectSqls);

        string insertSql = @$"
INSERT INTO school_class(id, sys_org_id, sys_org_branch_id, education_stage, class_number, `name`, full_name, short_name, grade_begin_year, grade_end_year, education_years, `status`, create_sys_user_id, create_time, is_deleted)
SELECT id, soid, sobid, es, cn, n, fn, sn, gby, gey, ey, 1, 2, CURRENT_TIMESTAMP, 0
FROM
({selectUnionAll}
) AS SCS
WHERE id NOT IN (SELECT id FROM school_class)
";

        await _rep.SqlNonQueryAsync(insertSql);
    }
    /// <summary>
    /// 获取班级信息
    /// </summary>
    /// <param name="sysOrgId"></param>
    /// <param name="sysOrgBranchId"></param>
    /// <param name="examGrade"></param>
    /// <param name="classNumber"></param>
    /// <returns></returns>
    public async Task<SchoolClassLiteOutput> GetSchoolClass(short sysOrgId, short? sysOrgBranchId, ExamGradeOutput examGrade, short classNumber)
    {
        var item = await _rep.DetachedEntities.FirstOrDefaultAsync(t => t.SysOrgId == sysOrgId && t.GradeBeginYear == examGrade.GradeBeginYear && t.ClassNumber == classNumber);
        if (item == null)
        {
            item = new()
            {
                Id = GetSchoolClassId(examGrade.EducationStage, sysOrgId, examGrade.GradeBeginYear, classNumber),
                ClassNumber = classNumber,
                SysOrgId = sysOrgId,
                SysOrgBranchId = sysOrgBranchId,
                EducationStage = examGrade.EducationStage,
                EducationYears = examGrade.EducationYears,
                GradeBeginYear = examGrade.GradeBeginYear,
                GradeEndYear = examGrade.GradeEndYear,
            };
            SetSchoolClassName(item, examGrade.EducationStage, examGrade.GradeBeginYear, classNumber);
            await item.InsertNowAsync();
        }
        return item.Adapt<SchoolClassLiteOutput>();
    }
    //public async Task<SchoolClassLiteOutput> GetSchoolClass(EducationStage educationStage, short sysOrgId, short? sysOrgBranchId, short gradeBeginYear, short classNumber){
    //    var item = await _rep.DetachedEntities.FirstOrDefaultAsync(t => t.SysOrgId == sysOrgId && t.GradeBeginYear == gradeBeginYear && t.ClassNumber == classNumber);
    //    if (item == null)
    //    {
    //        item = new()
    //        {
    //            Id = GetSchoolClassId(educationStage, sysOrgId, gradeBeginYear, classNumber),
    //            ClassNumber = classNumber,
    //            SysOrgId = sysOrgId,
    //            SysOrgBranchId = sysOrgBranchId,
    //            EducationStage = educationStage,
    //            EducationYears = examGrade.EducationYears,
    //            GradeBeginYear = examGrade.GradeBeginYear,
    //            GradeEndYear = examGrade.GradeEndYear,
    //        };
    //        SetSchoolClassName(item, examGrade.EducationStage, examGrade.GradeBeginYear, classNumber);
    //        await item.InsertAsync();
    //    }
    //    return item.Adapt<SchoolClassLiteOutput>();
    //}
    /// <summary>
    /// 获取班级ID
    /// </summary>
    /// <param name="educationStage">学段</param>
    /// <param name="sysOrgId">机构ID</param>
    /// <param name="gradeBeginYear">开始年份</param>
    /// <param name="classNumber">班号</param>
    /// <returns></returns>
    public long GetSchoolClassId(EducationStage educationStage, short sysOrgId, short gradeBeginYear, short classNumber)
    {
        return long.Parse($"{(short)educationStage}{sysOrgId.ToString().PadLeft(4, '0')}{gradeBeginYear.ToString().PadLeft(4, '0')}{classNumber.ToString().PadLeft(2, '0')}");
    }

    /// <summary>
    /// 根据ID获取学校班级信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<SchoolClassOutput> GetById(long id)
    {
        var item = await _rep.DetachedEntities.FirstOrDefaultAsync(x => x.Id == id) ?? throw Oops.Oh(ErrorCode.E2001);
        return item.Adapt<SchoolClassOutput>();
    }
    /// <summary>
    /// 根据级获取学校班级列表
    /// </summary>
    /// <param name="gradeBeginYear"></param>
    /// <returns></returns>
    public async Task<List<SchoolClassOutput>> GetListByGradeBeginYear(short gradeBeginYear)
    {
        if (!CurrentSysUserInfo.IsSuperAdmin && CurrentSysUserInfo.SysOrgId == 0)
        {
            return new();
        }
        var items = await _rep.DetachedEntities.Where(!CurrentSysUserInfo.IsSuperAdmin, t => t.SysOrgId == CurrentSysUserInfo.SysOrgId)
                                               .Where(gradeBeginYear != 0, t => t.GradeBeginYear == gradeBeginYear)
                                               .ProjectToType<SchoolClassOutput>().ToListAsync();
        return items;
    }
    /// <summary>
    /// 分页查询班级列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<PageResult<SchoolClassOutput>> QueryPageList(SchoolClassPageInput input)
    {
        var name = !string.IsNullOrEmpty(input.Name?.Trim());
        var ret = await _rep.DetachedEntities.Where((name, u => EF.Functions.Like(u.Name, $"%{input.Name.Trim()}%")))
                                             .Where(input.SysOrgId.HasValue, t => t.SysOrgId == input.SysOrgId)
                                             .Where(input.SysOrgBranchId.HasValue, t => t.SysOrgBranchId == input.SysOrgBranchId)
                                             .Where(input.GradeBeginYear.HasValue, t => t.GradeBeginYear == input.GradeBeginYear)
                                             .Where(input.ClassNumber.HasValue, t => t.ClassNumber == input.ClassNumber)
                                             .Where(input.Status.HasValue, t => t.Status == input.Status)
                                             .Where(!CurrentSysUserInfo.IsSuperAdmin, t => t.SysOrgId == CurrentSysUserInfo.SysOrgId)
                                             .ProjectToType<SchoolClassOutput>()
                                             .ToADPagedListAsync(input.PageIndex, input.PageSize);
        return ret;
    }


    #region 私有方法
    /// <summary>
    /// 设置班级名称
    /// </summary>
    /// <param name="sc">班级实体</param>
    /// <param name="educationStage">学段</param>
    /// <param name="gradeBeginYear">开始年份</param>
    /// <param name="classNumber">班号</param>
    private static void SetSchoolClassName(SchoolClass sc, EducationStage educationStage, short gradeBeginYear, short classNumber)
    {
        sc.FullName = BuildFullName(educationStage, gradeBeginYear, classNumber);
        sc.Name = BuildName(gradeBeginYear, classNumber);
        sc.ShortName = BuildShortName(classNumber);
    }
    private static string BuildFullName(EducationStage educationStage, short gradeBeginYear, short classNumber)
    {
        return $"{educationStage.GetDescription()}{gradeBeginYear}级{classNumber}班";
    }
    private static string BuildName(short gradeBeginYear, short classNumber)
    {
        return $"{gradeBeginYear}级{classNumber}班";
    }
    private static string BuildShortName(short classNumber)
    {
        return $"{classNumber}班";
    }
    #endregion
}
