using Hotline.Application.Snapshot.Contracts;
using Hotline.Orders;
using Hotline.Share.Dtos.Snapshot;
using Hotline.Share.Enums.CallCenter;
using Hotline.Share.Enums.Snapshot;
using Hotline.Share.Tools;
using Hotline.Snapshot;
using Hotline.Snapshot.IRepository;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XF.Domain.Dependency;

namespace Hotline.Application.Snapshot;

public class SnapshotPointsApplication : ISnapshotPointsApplication, IScopeDependency
{
    private readonly ISnapshotPointsRecordRepository _snapshotPointsRecordRepository;
    private readonly ICitizenRepository _citizenRepository;
    private readonly ISafetyTypeRepository _safetyTypeRepository;

    public SnapshotPointsApplication(ISnapshotPointsRecordRepository snapshotPointsRecordRepository, ICitizenRepository citizenRepository, ISafetyTypeRepository safetyTypeRepository)
    {
        _snapshotPointsRecordRepository = snapshotPointsRecordRepository;
        _citizenRepository = citizenRepository;
        _safetyTypeRepository = safetyTypeRepository;
    }

    public ISugarQueryable<PointsItemsOutDto> GetPointsItems(PointsItemsInDto dto)
    {
        var query = _snapshotPointsRecordRepository.Queryable()
            .LeftJoin<Citizen>((points, citizen) => points.UserId == citizen.Id)
            .LeftJoin<Order>((points, citizen, order) => order.Id == points.OrderId)
            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), (points, citizen) => citizen.PhoneNumber.Contains(dto.PhoneNumber!))
            .WhereIF(dto.County.NotNullOrEmpty(), (points, citizen, order) => order.County == dto.County)
            .WhereIF(dto.StartTime != null && dto.EndTime != null, (points, citizen) => points.CreationTime >= dto.StartTime && points.CreationTime <= dto.EndTime)
            .Where((points, citizen) => points.CreationTime >= dto.StartTime && points.CreationTime <= dto.EndTime)
            .GroupBy((points, citizen) => new { points.UserId, citizen.IsSecurityMax, citizen.Name, citizen.PhoneNumber })
            .Select((points, citizen) => new PointsItemsOutDto
            {
                IsSecurityMax = citizen.IsSecurityMax ?? false,
                Rank = SqlFunc.MappingColumn<int>("DENSE_RANK() OVER (ORDER BY SUM(CASE WHEN \"points\".\"Direction\" = 0 THEN \"points\".\"Points\" ELSE 0 END) DESC)"),
                OutTotalPoint = SqlFunc.AggregateSum(SqlFunc.IIF(points.Direction == EPointsDirection.Out, points.Points, 0)),
                OutPoints = SqlFunc.AggregateSum(SqlFunc.IIF(points.Direction == EPointsDirection.Out && points.Source == EPointsSource.Audit, points.Points, 0)),
                TotalPoints = SqlFunc.AggregateSum(points.Points),
                InTotalPoint = SqlFunc.AggregateSum(SqlFunc.IIF(points.Direction == EPointsDirection.In, points.Points, 0)),
                UserName = citizen.Name!,
                PhoneNumber = citizen.PhoneNumber,
                UserId = points.UserId,
            })
            .OrderByPropertyNameIF(dto.SortField.NotNullOrEmpty() && dto.SortRule == 0, dto.SortField, OrderByType.Desc)
            .OrderByPropertyNameIF(dto.SortField.NotNullOrEmpty() && dto.SortRule == 1, dto.SortField, OrderByType.Asc);
#if DEBUG
        var sql = query.ToSqlString();
#endif
        return query;
    }

    public async Task UpdateIsSecurityMaxAsync(UpdateIsSecurityMaxAsync dto, CancellationToken token)
    {
        await _citizenRepository.Updateable()
            .SetColumns(citizen => citizen.IsSecurityMax, dto.IsSecurityMax)
            .Where(citizen => citizen.Id == dto.UserId)
            .ExecuteCommandAsync(token);
        await _citizenRepository.Queryable()
            .Includes(m => m.SafetyTypes)
            .Where(m => m.Id == dto.UserId)
            .FirstAsync(token)
            .Then(async citizen =>
            {
                await _safetyTypeRepository.Queryable()
                    .Where(m => m.Name == "安全卫士")
                    .FirstAsync(token)
                    .Then(async safetyType =>
                    {
                        if (dto.IsSecurityMax)
                            citizen.SafetyTypes.Add(safetyType);
                        else
                        {
                            var delete = citizen.SafetyTypes.Where(m => m.Name == "安全卫士").ToList();
                            foreach (var item in delete)
                            {
                                citizen.SafetyTypes.Remove(item);
                            }
                        }
                        await _citizenRepository.UpdateNav(citizen).Include(m => m.SafetyTypes)
                                .ExecuteCommandAsync();
                    });
            });
    }
}
