using Dapper;
using Ewide.Core.Extension;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ewide.Application.Service
{
    public class InspectionOrgDirService : IInspectionOrgDirService, IDynamicApiController, ITransient
    {
        private readonly IDapperRepository _dapperRep;

        private readonly IRepository<BsInspectionOrgDirStage> _dirStageRep;
        private readonly IRepository<BsInspectionOrgDirDetail> _dirDetailRep;
        private readonly IRepository<BsInspectionOrg> _orgRep;

        public InspectionOrgDirService(
            IDapperRepository dapperRep,

            IRepository<BsInspectionOrgDirStage> dirStageRep,
            IRepository<BsInspectionOrgDirDetail> dirDetailRep,
            IRepository<BsInspectionOrg> orgRep
        )
        {
            _dapperRep = dapperRep;

            _dirStageRep = dirStageRep;
            _dirDetailRep = dirDetailRep;
            _orgRep = orgRep;
        }

        [HttpPost("/inspectionOrgDir/page")]
        public async Task<dynamic> Page([FromBody] InspectionOrgDirPageInput input)
        {
            var sql = "SELECT * FROM bs_inspection_org_dir_stage WHERE Status = 1 ORDER BY PublishTime DESC";
            return await _dapperRep.QueryPageDataDynamic(sql, input, filterFields: new[] { nameof(BsInspectionOrgDirStage.No) });
        }

        /// <summary>
        /// 获取当前名录打分列表
        /// </summary>
        /// <returns></returns>
        [HttpPost("/inspectionOrgDir/listScore")]
        public async Task<dynamic> ListScore()
        {
            var sql = @"SELECT * FROM
(
SELECT
	IO.Id,
	IO.`Code`,
	IO.`Name`,
	CASE WHEN LIODD.ScoreResult IS NULL THEN 1 ELSE 0 END IsNew,
	LIODD.ScoreResult PrevScoreResult,
	TIODD.Score,
	TIODD.ScoreResult
FROM
(
	SELECT 
		*,
		(SELECT Id FROM bs_inspection_org_dir_stage WHERE Status = 1 ORDER BY CreatedTime DESC LIMIT 1) PrevStageId,
		(SELECT Id FROM bs_inspection_org_dir_stage WHERE Status = 0) CurrentStageId
	FROM
	bs_inspection_org
) IO
LEFT JOIN bs_inspection_org_dir_detail LIODD ON IO.PrevStageId = LIODD.StageId AND IO.Id = LIODD.OrgId
LEFT JOIN bs_inspection_org_dir_detail TIODD ON IO.CurrentStageId = TIODD.StageId AND IO.Id = TIODD.OrgId
WHERE IO.Status = 1
) T ORDER BY IsNew DESC, `Code`";
            return await _dapperRep.QueryAsync(sql);
        }

        [HttpGet("/inspectionOrgDir/detail")]
        public async Task<dynamic> Detail()
        {
            return await _dirStageRep.DetachedEntities.FirstOrDefaultAsync(p => p.Status.Equals(0));
        }

        private int ScoreResult(int score, int? prevScoreResult)
        {
            int result;
            if (score >= 10)
            {
                result = 1;
            }
            else if (score >= 8)
            {
                result = 2;
            }
            else if (score >= 6)
            {
                result = 3;
            }
            else
            {
                result = 4;
            }

            if (prevScoreResult.GetValueOrDefault(0).Equals(3) && result.Equals(3))
            {
                result = 4;
            }

            return result;
        }

        [HttpPost("/inspectionOrgDir/saveScore")]
        [UnitOfWork]
        public async Task SaveScore([FromBody] InspectionOrgDirSaveInput input)
        {
            var stageId = input.Id;

            var isAdd = false;
            // 新增修改名录主表
            if (String.IsNullOrEmpty(stageId))
            {
                // 新增
                // 如果存在未公布的名录,则失败
                var isExistUnpublished = await _dirStageRep.DetachedEntities.AnyAsync(p => p.Status.Equals(0));
                if(isExistUnpublished)
                    throw Oops.Oh("存在未公布的名录，无法新增");

                var isExistNo = await _dirStageRep.DetachedEntities.AnyAsync(p => p.No.Equals(input.No));
                if (isExistNo)
                    throw Oops.Oh("名录期号已存在");

                var stage = input.Adapt<BsInspectionOrgDirStage>();
                stageId = Guid.NewGuid().ToString().ToLower();
                stage.Id = stageId;

                await stage.InsertAsync();

                isAdd = true;
            }
            else
            {
                var isExistNo = await _dirStageRep.DetachedEntities.AnyAsync(p => p.No.Equals(input.No) && !p.Id.Equals(input.Id));
                if (isExistNo)
                    throw Oops.Oh("名录期号已存在");

                // 修改
                var stage = await _dirStageRep.FirstOrDefaultAsync(p => p.Id.Equals(input.Id));
                stage.No = input.No;

                await stage.UpdateAsync();
            }

            var prevStage = await _dirStageRep.DetachedEntities.OrderByDescending(p => p.CreatedTime).FirstOrDefaultAsync(p => !p.Id.Equals(stageId));
            var prevDetails = new List<BsInspectionOrgDirDetail>();
            if (prevStage != null)
            {
                prevDetails = await _dirDetailRep.DetachedEntities.Where(p => p.StageId.Equals(prevStage.Id)).ToListAsync();
            }

            // 新增修改名录详细表
            foreach (var detail in input.Detail)
            {
                var prevDetail = prevDetails.FirstOrDefault(p => p.OrgId.Equals(detail.OrgId));
                var scoreResult = ScoreResult(detail.Score, prevDetail?.ScoreResult);

                if (!isAdd)
                {
                    // 名录已经存在时,判断每个机构的打分记录是否已经存在
                    var _data = await _dirDetailRep.FirstOrDefaultAsync(p => p.OrgId.Equals(detail.OrgId) && p.StageId.Equals(stageId));
                    if (_data != null)
                    {
                        _data.Score = detail.Score;
                        _data.ScoreResult = scoreResult;
                        await _data.UpdateAsync();
                        continue;
                    }
                }

                var data = detail.Adapt<BsInspectionOrgDirDetail>();
                data.StageId = stageId;
                data.ScoreResult = scoreResult;

                await data.InsertAsync();
            }
        }

        [HttpGet("/inspectionOrgDir/preview")]
        public async Task<InspectionOrgDirPreviewOutput> Preview()
        {
            var stage = await _dirStageRep.FirstOrDefaultAsync(p => p.Status.Equals(0));
            if (stage == null)
            {
                // 当前没有需要发布的名录
                return null;
            }

            var count = await _dirDetailRep.Where(p => p.StageId.Equals(stage.Id) && !p.ScoreResult.Equals(4)).CountAsync();

            var sql = @"SELECT * FROM
(
SELECT
	IO.Id,
	IO.`Code`,
	IO.`Name`,
	IO.Address,
	CASE 
		WHEN TIODD.ScoreResult = 4 THEN -1
		WHEN LIODD.ScoreResult IS NULL THEN 1
		ELSE 0 END `Status`
FROM
(
	SELECT 
		*,
		(SELECT Id FROM bs_inspection_org_dir_stage WHERE Status = 1 ORDER BY CreatedTime DESC LIMIT 1) PrevStageId,
		(SELECT Id FROM bs_inspection_org_dir_stage WHERE Status = 0) CurrentStageId
	FROM
	bs_inspection_org
) IO
LEFT JOIN bs_inspection_org_dir_detail LIODD ON IO.PrevStageId = LIODD.StageId AND IO.Id = LIODD.OrgId
LEFT JOIN bs_inspection_org_dir_detail TIODD ON IO.CurrentStageId = TIODD.StageId AND IO.Id = TIODD.OrgId
WHERE (LIODD.ScoreResult IS NULL OR LIODD.ScoreResult < 4) AND IO.`Status` >= 0
) T ORDER BY `Status` DESC, `Code`";
            var list = await _dapperRep.QueryAsync(sql);

            return new InspectionOrgDirPreviewOutput
            {
                Stage = stage,
                Count = count,
                List = list
            };
        }

        [HttpPost("/inspectionOrgDir/publish")]
        [UnitOfWork]
        public async Task Publish()
        {
            var stage = await _dirStageRep.FirstOrDefaultAsync(p => p.Status.Equals(0));
            if (stage == null)
                throw Oops.Oh("当前名录数据错误");

            // 评分详情
            var details = await _dirDetailRep.DetachedEntities.Where(p => p.StageId.Equals(stage.Id)).ToListAsync();
            // 当前需打分的机构
            var orgIds = await _orgRep.DetachedEntities.Where(p => p.Status != InspectionOrgStatus.Delisting && p.Status != InspectionOrgStatus.Revoke).Select(p => p.Id).ToListAsync();
            if (orgIds.Any(p => !details.Select(p => p.OrgId).Contains(p)))
                throw Oops.Oh("存在未评分的机构");

            // 往期名录
            var prevStage = await _dirStageRep.DetachedEntities.OrderByDescending(p => p.CreatedTime).FirstOrDefaultAsync(p => !p.Id.Equals(stage.Id));
            // 往期机构
            var prevDetails = await _dirDetailRep.DetachedEntities.Where(p => p.StageId.Equals(prevStage.Id)).ToListAsync();
            // 往期黄牌机构
            var prevFilteredDetailOrgIds = new List<string>();
            if (prevStage != null)
            {
                // 获取往期黄牌机构
                prevFilteredDetailOrgIds = prevDetails.Where(p => p.ScoreResult.Equals(3)).Select(p => p.OrgId).ToList();
            }

            // 对除名的机构修改状态
            var revmoeCount = 0;
            var mayBeRemovedDetails = details.Where(p => p.ScoreResult.Equals(3) || p.ScoreResult.Equals(4)).ToList();
            foreach (var detail in mayBeRemovedDetails)
            {
                if ((detail.ScoreResult.Equals(3) && prevFilteredDetailOrgIds.Contains(detail.OrgId))
                    || detail.ScoreResult.Equals(4))
                {
                    // 本期及往期为黄牌或者本期为红牌的,进行除名
                    var org = await _orgRep.FirstOrDefaultAsync(p => p.Id.Equals(detail.OrgId));
                    org.Status = InspectionOrgStatus.Delisting;
                    await org.UpdateIncludeAsync(new[] { nameof(BsInspectionOrg.Status) });
                    revmoeCount++;
                }
            }

            // 新增机构数量
            var newDetailsCount = details.Where(p => (p.ScoreResult.Equals(1) || p.ScoreResult.Equals(2)) && !prevDetails.Select(p => p.OrgId).Contains(p.OrgId)).Count();

            // 总数减去除名
            stage.OrgAmount = details.Count - revmoeCount;
            // 除名
            stage.RemovedOrgAmount = revmoeCount;
            // 新增
            stage.NewOrgAmount = newDetailsCount;

            stage.Status = 1;
            stage.PublishTime = DateTime.Now;
            await stage.UpdateAsync();
        }
    }
}
