using DocumentFormat.OpenXml.Vml.Office;
using Hotline.Application.Snapshot.Contracts;
using Hotline.Caching.Interfaces;
using Hotline.Orders;
using Hotline.Settings;
using Hotline.Share.Dtos.Snapshot;
using Hotline.Share.Tools;
using Hotline.Snapshot;
using Hotline.Snapshot.IRepository;
using Hotline.ThirdAccountDomainServices;
using Hotline.Tools;
using Mapster;
using NPOI.POIFS.Properties;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Application.Snapshot;

public class SnapshotUserApplication : ISnapshotUserApplication, IScopeDependency
{
    private readonly ICitizenRepository _citizenRepository;
    private readonly ISystemDicDataCacheManager _dicData;
    private readonly IRepository<SafetyType> _safetyTypeRepository;

    public SnapshotUserApplication(ICitizenRepository citizenRepository, ISystemDicDataCacheManager dicData, IRepository<SafetyType> safetyTypeRepository)
    {
        _citizenRepository = citizenRepository;
        _dicData = dicData;
        _safetyTypeRepository = safetyTypeRepository;
    }

    public async Task AddCitizenRelationSafetyType(AddCitizenRelationSafetyTypeInDto dto, CancellationToken token)
    {
        dto.ValidateObject();

        var safeType = new SafetyType
        {
            Id = dto.SafetyTypeId,
            Citizens = []
        };
        var citizenExists = await _citizenRepository.Queryable()
            .LeftJoin<CitizenRelationSafetyType>((citizen, relation) => citizen.Id == relation.CitizenId)
            .Where((citizen, relation) => dto.CitizenIds.Contains(citizen.Id) && relation.SafetyTypeId == dto.SafetyTypeId)
            .Select((citizen, relation) => citizen.Id)
            .ToListAsync(token);
        dto.CitizenIds = dto.CitizenIds.Except(citizenExists).ToList();
        foreach (var item in dto.CitizenIds)
        {
            safeType.Citizens.Add(new Citizen { Id = item });
        }

        await _safetyTypeRepository.AddNav(safeType)
            .Include(m => m.Citizens, new InsertNavOptions()
            {
                ManyToManyNoDeleteMap = true
            })
            .ExecuteCommandAsync();
    }

    public ISugarQueryable<CitizenRelationSafetyTypeOutDto> GetCitizenRelationSafetyType(CitizenRelationSafetyTypeInDto dto)
    {
        var query = _citizenRepository.Queryable()
            .LeftJoin<CitizenRelationSafetyType>((citizen, relation) => citizen.Id == relation.CitizenId)
            .LeftJoin<SafetyType>((citizen, relation, safety) => relation.SafetyTypeId == safety.Id)
            .WhereIF(dto.SafetyTypeId.NotNullOrEmpty(), (citizen, relation, safety) => safety.Id == dto.SafetyTypeId)
            .WhereIF(dto.Name.NotNullOrEmpty(), (citizen, relation, safety) => citizen.Name.Contains(dto.Name))
            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), (citizen, relation, safety) => citizen.PhoneNumber.Contains(dto.PhoneNumber))
            .Where((citizen, relation, safety) => safety.Id != null)
            .Select((citizen, relation, safety) => new CitizenRelationSafetyTypeOutDto
            {
                CitizenId = citizen.Id,
                CitizenName = citizen.Name,
                PhoneNumber = citizen.PhoneNumber,
                SafetyTypeName = safety.Name,
                SafetyTypeId = safety.Id
            });
        return query;
    }

    public async Task DeleteCitizenRelationSafetyAsync(DeleteCitizenRelationSafetyTypeInDto dto)
    {
        foreach (var item in dto.Items)
        {
            var citizen = await _citizenRepository.Queryable()
                .Includes(m => m.SafetyTypes)
                .Where(m => m.Id == item.CitizenId)
                .FirstAsync();
            var deleteSafetyType = citizen.SafetyTypes.FirstOrDefault(m => m.Id == item.SafetyTypeId);
            if (deleteSafetyType == null) continue;

            citizen.SafetyTypes.Remove(deleteSafetyType);
            _citizenRepository.UpdateNav(citizen)
                .Include(m => m.SafetyTypes)
                .ExecuteCommand();
        }
    }

    public ISugarQueryable<GetThirdCitizenOutDto> GetThirdCitizenAsync(GetThirdCitizenInDto dto)
    {
        var query = _citizenRepository.Queryable(includeDeleted: true)
            .LeftJoin<ThirdAccount>((citizen, third) => citizen.Id == third.ExternalId)
            .LeftJoin<CitizenRelationSafetyType>((citizen, third, relation) => relation.CitizenId == citizen.Id && relation.SafetyTypeId == dto.SafetyTypeId)
            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), (citizen, third) => citizen.PhoneNumber.Contains(dto.PhoneNumber))
            .WhereIF(dto.SafetyTypeId.NotNullOrEmpty(), (citizen, third, relation) => relation.CitizenId == null)
            .Select((citizen, third, relation) => new GetThirdCitizenOutDto 
            {
                CitizenId = citizen.Id
            }, true);
#if DEBUG
        var sql = query.ToSqlString();
#endif

        return query;
    }
}
