using AsbCloudApp.Data;
using AsbCloudApp.Data.DrillTestReport;
using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudInfrastructure.Services.DrillTestReport
{
    public class DrillTestReportService : IDrillTestReportService
    {
        private readonly IWellService wellService;
        private readonly IDrillTestRepository drillTestRepository;
        private readonly ITelemetryService telemetryService;
        private readonly IReportMakerService<DrillTestReportDataDto> drillTestReportMakerService;

        public DrillTestReportService(
            IWellService wellService,
            IDrillTestRepository drillTestRepository,
            ITelemetryService telemetryService,
            IReportMakerService<DrillTestReportDataDto> drillTestReportMakerService)
        {
            this.wellService = wellService;
            this.drillTestRepository = drillTestRepository;
            this.telemetryService = telemetryService;
            this.drillTestReportMakerService = drillTestReportMakerService;
        }

        public async Task<(string fileName, Stream stream)> GenerateAsync(int idWell, int id, CancellationToken cancellationToken)
        {
            var well = wellService.GetOrDefault(idWell);
            if (well is null)
                throw new ArgumentInvalidException(nameof(idWell), $"Well with id: {idWell} does not exist.");
            if (well.IdTelemetry is null)
                throw new ArgumentInvalidException(nameof(well.IdTelemetry), $"Well with id: {idWell} does not have telemetry.");

            var dto = await drillTestRepository.GetAsync(well.IdTelemetry.Value, id, cancellationToken);
           
            var report = new DrillTestReportDataDto()
            {
                Data = dto,
                Caption = string.Format("Месторождение: {0}, куст: {1}, скважина: {2}", 
                    well.Deposit ?? "-", 
                    well.Cluster ?? "-", 
                    well.Caption ?? "-"),
                Date = DateTime.Now,
            };

            var fileName = string.Format("Drill_test_{0}.xlsx", dto.TimeStampStart.ToString("dd.mm.yyyy_HH_MM_ss"));
            var stream = await drillTestReportMakerService.MakeReportAsync(report, cancellationToken);

            return (fileName, stream);
        }


        public async Task<PaginationContainer<DrillTestReportInfoDto>> GetListAsync(int idWell, FileReportRequest request, CancellationToken cancellationToken)
        {
            var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell);
            if (telemetry is null)
                throw new Exception($"Telemetry with idWell: {idWell} does not exist.");

            var result = new PaginationContainer<DrillTestReportInfoDto>
            {
                Skip = request.Skip ?? 0,
                Take = request.Take ?? 10,
                Items = Enumerable.Empty<DrillTestReportInfoDto>()
            };

            var reports = new List<DrillTestReportInfoDto>();
            var timezone = telemetryService.GetTimezone(telemetry.Id);

            var dtos = await drillTestRepository.GetAllAsync(telemetry.Id, request, cancellationToken);
            foreach (var dto in dtos)
            {
                var remoteDateTime = dto.TimeStampStart.ToRemoteDateTime(timezone.Hours);

                reports.Add(new DrillTestReportInfoDto
                {
                    FileName = string.Format("Drill_test_{0}", dto.TimeStampStart.DateTime),
                    DrillDepth = (dto.Params
                        .Where(p => p.DepthDrillStep.HasValue)
                        .Sum(x => x.DepthDrillStep) ?? 0) + dto.DepthStart,
                    DateTime = dto.TimeStampStart.DateTime,
                    Id = dto.Id,
                });
            }

            result.Items = reports;

            return result;
        }
    }
}