using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudDb.Model;
using AsbCloudDb.Model.WellSections;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Npgsql;

namespace AsbCloudInfrastructure.Repository;

public class WellSectionPlanRepository : CrudWellRelatedRepositoryBase<WellSectionPlanDto, WellSectionPlan>,
   IWellSectionPlanRepository
{
   public WellSectionPlanRepository(IAsbCloudDbContext context)
      : base(context, query => query.Include(w => w.SectionType))
   {
   }

   public override async Task<int> InsertAsync(WellSectionPlanDto item, CancellationToken token)
   {
      var id = 0;

      try
      {
         id = await base.InsertAsync(item, token);
      }
      catch (DbUpdateException ex)
      {
         if (ex.InnerException is PostgresException pgException)
            HandlePostgresException(pgException, item);
         else
            throw;
      }

      return id;
   }

   public override async Task<int> UpdateAsync(WellSectionPlanDto item, CancellationToken token)
   {
      var id = 0;

      try
      {
         id = await base.UpdateAsync(item, token);
      }
      catch (DbUpdateException ex)
      {
         if (ex.InnerException is PostgresException pgException)
            HandlePostgresException(pgException, item);
         else
            throw;
      }

      return id;
   }

   public async Task<IEnumerable<WellSectionTypeDto>> GetWellSectionTypesAsync(int idWell, CancellationToken cancellationToken)
   {
      var query = from wellSectionType in dbContext.WellSectionTypes
         join wellSectionPlan in dbContext.WellSectionsPlan on wellSectionType.Id equals wellSectionPlan.IdSectionType
         where wellSectionPlan.IdWell == idWell
         orderby wellSectionType.Order
         select wellSectionType;

      IEnumerable<WellSectionType> entities = await query.ToArrayAsync(cancellationToken);

      if (!entities.Any())
         entities = await dbContext.WellSectionTypes.OrderBy(w => w.Order).ToArrayAsync(cancellationToken);

      return entities.Select(w => w.Adapt<WellSectionTypeDto>());
   }
   
   private static void HandlePostgresException(PostgresException pgException, WellSectionPlanDto wellSectionPlan)
   {
      if (pgException.SqlState == PostgresErrorCodes.UniqueViolation)
         throw new ArgumentInvalidException($"Секция уже добавлена в конструкцию скважины",
            nameof(wellSectionPlan.IdSectionType));

   } 
}