using AsbCloudApp.Data;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudInfrastructure.Services
{
    public class ClusterService : IClusterService
    {
        private readonly IAsbCloudDbContext db;

        public ClusterService(IAsbCloudDbContext db)
        {
            this.db = db;
        }

        public async Task<IEnumerable<DepositDto>> GetDepositsAsync(int idCompany,
            CancellationToken token = default)
        {
            var wellEntities = await (from well in db.Wells
                .Include(w => w.RelationCompaniesWells)
                .Include(w => w.WellType)
                .Include(w => w.Cluster)
                .ThenInclude(c => c.Deposit)
                                      where well.RelationCompaniesWells.Any(r => r.IdCompany == idCompany)
                                      select well).ToListAsync(token)
                                .ConfigureAwait(false);

            var gDepositEntities = wellEntities
                .GroupBy(w => w.Cluster)
                .GroupBy(c => c.Key.Deposit);

            var dtos = gDepositEntities.Select(gDeposit => new DepositDto
            {
                Id = gDeposit.Key.Id,
                Caption = gDeposit.Key.Caption,
                Latitude = gDeposit.Key.Latitude,
                Longitude = gDeposit.Key.Longitude,
                Description = "",
                Clusters = gDeposit.Select(gCluster => new ClusterDto
                {
                    Id = gCluster.Key.Id,
                    Caption = gCluster.Key.Caption,
                    Latitude = gCluster.Key.Latitude,
                    Longitude = gCluster.Key.Longitude,
                    Description = "",
                    Wells = gCluster.Select(well => new WellDto
                    {
                        Id = well.Id,
                        Caption = well.Caption,
                        Latitude = well.Latitude,
                        Longitude = well.Longitude,
                        WellType = well.WellType?.Caption,
                        Cluster = gCluster.Key.Caption,
                        Deposit = gDeposit.Key.Caption,
                    }),
                }),
            });

            return dtos;
        }

        public async Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
            CancellationToken token = default)
        {
            var entities = await db.GetWellsForCompany(idCompany)
                        .Select(e => e.Cluster)
                        .Distinct()
                        .AsNoTracking()
                        .ToListAsync(token)
                        .ConfigureAwait(false);

            var dtos = entities.Adapt<ClusterDto>();

            return dtos;
        }

        public async Task<IEnumerable<ClusterDto>> GetClustersAsync(int idCompany,
            int depositId, CancellationToken token = default)
        {
            var entities = await db.GetWellsForCompany(idCompany)
                        .Select(e => e.Cluster)
                        .Where(e => e.IdDeposit == depositId)
                        .Distinct()
                        .AsNoTracking()
                        .ToListAsync(token)
                        .ConfigureAwait(false);

            var dtos = entities.Adapt<ClusterDto>();

            return dtos;
        }

        public async Task<IEnumerable<WellDto>> GetWellsAsync(int idCompany,
            int idCluster, CancellationToken token = default)
        {
            var entities = await db.GetWellsForCompany(idCompany)
                .Where(e => e.IdCluster == idCluster)
                .AsNoTracking()
                .ToListAsync(token)
                .ConfigureAwait(false);

            var dtos = entities.Select(e => new WellDto
            {
                Id = e.Id,
                Caption = e.Caption,
                Latitude = e.Latitude,
                Longitude = e.Longitude,
                Cluster = e.Cluster.Caption,
                Deposit = e.Cluster.Deposit.Caption,
            });

            return dtos;
        }
    }
}