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));

	} 
}