using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudInfrastructure.Repository
{
    public class DrillTestRepository : IDrillTestRepository
    {
        private readonly IAsbCloudDbContext db;

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

        public async Task<IEnumerable<DrillTestDto>> GetAllAsync(int idTelemetry, FileReportRequest request, CancellationToken cancellationToken)
        {
            var query = db.DrillTests
                .Where(d => d.IdTelemetry == idTelemetry)
                .Include(d => d.Telemetry)
                .AsNoTracking();

            if (request.GeDate.HasValue)
            {
                var startDateUTC = new DateTimeOffset(request.GeDate.Value.Year, request.GeDate.Value.Month, request.GeDate.Value.Day, 0, 0, 0, TimeSpan.Zero);
                query = query.Where(q => q.TimeStampStart >= startDateUTC);
            }
            if (request.LeDate.HasValue)
            {
                var finishDateUTC = new DateTimeOffset(request.LeDate.Value.Year, request.LeDate.Value.Month, request.LeDate.Value.Day, 0, 0, 0, TimeSpan.Zero);
                query = query.Where(q => q.TimeStampStart <= finishDateUTC);
            }

            var entities = await query.ToListAsync(cancellationToken);
            var dtos = entities.Select(e => Convert(e));

            return dtos;
        }


        public async Task<DrillTestDto> GetAsync(int idTelemetry, int id, CancellationToken cancellationToken)
        {
            var drillTest = await db.DrillTests
                .Where(d => d.Id == id)
                .Include(d => d.Telemetry)
                .Where(d => d.Telemetry.Id == idTelemetry)
                .FirstOrDefaultAsync(cancellationToken);

            if (drillTest is null)
                throw new ArgumentInvalidException(new string[] { nameof(id), nameof(idTelemetry) }, $"Drill test with id: {id} and idTelemetry: {idTelemetry} does not exist.");

            var dto = Convert(drillTest);

            return dto;
        }

        public async Task<int> SaveDataAsync(int idTelemetry, DrillTestDto dto, CancellationToken token)
        {
            var entity = dto.Adapt<DrillTest>();
            entity.IdTelemetry = idTelemetry;
            db.DrillTests.Add(entity);
            var result = await db.SaveChangesAsync(token);
            return result;
        }

        private DrillTestDto Convert(DrillTest entity)
        {
            var dto = entity.Adapt<DrillTestDto>();
            dto.TimeStampStart = dto.TimeStampStart.ToRemoteDateTime(dto.Telemetry?.TimeZone?.Hours ?? 0);
            return dto;
        }
    }
}