using AsbCloudApp.Data.DailyReport;
using AsbCloudApp.Data.DailyReport.Blocks.Sign;
using AsbCloudApp.Data.DailyReport.Blocks.Subsystems;
using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb;
using AsbCloudDb.Model;
using AsbCloudDb.Model.DailyReports;
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 DailyReportRepository : CrudRepositoryBase<DailyReportDto, DailyReport>,
    IDailyReportRepository
{
    private IWellService wellService;

    public DailyReportRepository(IAsbCloudDbContext dbContext, IWellService wellService)
    : base(dbContext)
    {
        this.wellService = wellService;
    }

    public async Task<IEnumerable<DailyReportDto>> GetAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken)
    {
        var skip = request.Skip ?? 0;
        var take = request.Take ?? 10;

        var query = GetQuery().Where(d => d.IdWell == idWell);

        if (request.GeDate.HasValue)
            query = query.Where(d => d.Date >= request.GeDate.Value);

        if (request.LeDate.HasValue)
            query = query.Where(d => d.Date <= request.LeDate.Value);

        query = request.SortFields?.Any() == true ?
            query.SortBy(request.SortFields) :
            query.OrderBy(d => d.Date);

        var entities = await query
            .Skip(skip)
            .Take(take)
            .AsNoTracking()
        .ToArrayAsync(cancellationToken);

        var timezoneOffset = wellService.GetTimezone(idWell).Offset;
        var dtos = entities.Select(entity => Convert(entity, timezoneOffset));

        return dtos;
    }

    public async Task<DailyReportDto?> GetOrDefaultAsync(int idWell, DateOnly date, CancellationToken cancellationToken)
    {
        var entity = await GetQuery()
            .AsNoTracking()
            .SingleOrDefaultAsync(d => d.IdWell == idWell && d.Date == date, cancellationToken);

        var timezoneOffset = wellService.GetTimezone(idWell).Offset;
        
        return entity is null ? null : Convert(entity, timezoneOffset);
    }

    private static DailyReportDto Convert(DailyReport src, TimeSpan timezoneOffset)
    {
        var dto = new DailyReportDto
        {
            Id = src.Id,
            IdWell = src.IdWell,
            DateLastUpdate = src.DateLastUpdate?.ToOffset(timezoneOffset),
            Date = src.Date,
            SignBlock = src.SignBlock?.Adapt<SignBlockDto>(),
            TimeBalanceBlock = src.TimeBalanceBlock?.Adapt<TimeBalanceBlockDto>(),
            SubsystemBlock = src.SubsystemBlock?.Adapt<SubsystemBlockDto>()
        };

        return dto;
    }
}