using AsbCloudApp.Data;
using AsbCloudApp.Data.User;
using AsbCloudApp.Exceptions;
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 WellContactService : IWellContactService
    {
        private readonly IAsbCloudDbContext db;

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

        public async Task<IEnumerable<ContactDto>> GetAllAsync(int wellId, int contactTypeId, CancellationToken token)
        {
            var query = db.Contacts
                .Where(c => c.IdCompanyType == contactTypeId)
                .Where(c => c.IdWell == wellId)
                .Select(c => c.Adapt<ContactDto>());

            var entities = await query.AsNoTracking()
              .ToArrayAsync(token);

            return entities;
        }

        public async Task<ContactDto?> GetAsync(int idWell, int id, CancellationToken token)
        {
            var dbContact = await GetContact(idWell, id, token);

            var result = dbContact?.Adapt<ContactDto>();

            return result;
        }

        public async Task<IEnumerable<CompanyTypeDto>> GetTypesAsync(CancellationToken token)
        {
            var query = db.CompaniesTypes
                .Where(t => t.IsContact)
                .OrderBy(t => t.Order);

            var entities = await query.AsNoTracking()
               .ToArrayAsync(token);

            var dtos = entities.Adapt<IEnumerable<CompanyTypeDto>>();

            return dtos;
        }

        public async Task<int> InsertAsync(ContactDto contactDto, CancellationToken token)
        {
            var entity = contactDto.Adapt<Contact>();

            db.Contacts.Add(entity);

            await db.SaveChangesAsync(token).ConfigureAwait(false);
            return entity.Id;
        }


        public async Task<int> UpdateAsync(ContactDto contactDto, CancellationToken token)
        {
            var dbContact = await GetContact(contactDto.IdWell, contactDto.Id, token);
            if (dbContact is null)
                throw new ForbidException("Contact doesn't exist");

            var entity = contactDto.Adapt<Contact>();
            db.Contacts.Update(entity);

            return await db.SaveChangesAsync(token);
        }

        public async Task<int> DeleteAsync(int idWell, int id, CancellationToken token)
        {
            var dbContact = await GetContact(idWell, id, token);
            if (dbContact is null)
                throw new ForbidException("Contact doesn't exist");

            db.Contacts.Remove(dbContact);
            return await db.SaveChangesAsync(token);
        }

        private async Task<Contact?> GetContact(int idWell, int idContact, CancellationToken token)
        {
            var contact = await db.Contacts
                .Where(c => c.IdWell == idWell)
                .Where(c => c.Id == idContact)
                .AsNoTracking()
                .FirstOrDefaultAsync(token);

            return contact;
        }
    }
}