using AutoMapper;
using Microsoft.EntityFrameworkCore;
using SecureSharing.Business.Dtos;
using SecureSharing.Business.Infrastructure;
using SecureSharing.Business.Interfaces;
using SecureSharing.Data.Data;
using SecureSharing.Data.DbContexts;

namespace SecureSharing.Business.Services;

public sealed class MessageService : IMessageService
{
    private readonly AppDbContext _dbContext;
    private readonly IMapper _mapper;

    public MessageService(AppDbContext dbContext, IMapper mapper)
    {
        _dbContext = dbContext;
        _mapper = mapper;
    }

    public async Task<Guid> Create(MessageDto messageDto, PeriodOfValidity chosenPeriod)
    {
        var message = _mapper.Map<Message>(messageDto);
        message.ExpiryDate = chosenPeriod switch
        {
            PeriodOfValidity.ONE_TIME => null,
            PeriodOfValidity.ONE_DAY => DateTime.UtcNow.AddMinutes(1),
            PeriodOfValidity.ONE_HOUR => DateTime.UtcNow.AddHours(1),
            PeriodOfValidity.ONE_WEEK => DateTime.UtcNow.AddDays(7),
            _ => null
        };

        await _dbContext.Messages.AddAsync(message);
        await _dbContext.SaveChangesAsync();
        return Guid.Parse(message.Code);
    }

    public async Task<List<string>> DeleteExpiredMessages()
    {
        var result = await _dbContext.Messages
            .Where(m => (m.ExpiryDate != null && m.ExpiryDate <= DateTime.UtcNow) || !m.IsValid)
            .ToListAsync();
        
        var toReturn = result.Select(x => x.Code).ToList();
        _dbContext.RemoveRange(result);
        await _dbContext.SaveChangesAsync();

        return toReturn;
    }

    public async Task InvalidateMessage(int id)
    {
        var message = await _dbContext.Messages
            .Where(m => m.Id == id)
            .FirstOrDefaultAsync();
        
        message!.IsValid = false;
        await _dbContext.SaveChangesAsync();
    }

    public async Task<bool> Delete(int id)
    {
        var messageDto = await GetById(id);
        if (messageDto is null)
            return false;

        _dbContext.Messages.Remove(_mapper.Map<Message>(messageDto));
        try
        {
            await _dbContext.SaveChangesAsync();
        }
        catch (DbUpdateException)
        {
            return false;
        }

        return true;
    }

    public async Task<IEnumerable<MessageDto>> GetAll()
    {
        var result = await _dbContext.Messages
            .AsNoTracking()
            .ToListAsync();
        
        var mappedResult = _mapper.Map<IEnumerable<MessageDto>>(result);
        return mappedResult;
    }


    public async Task<MessageDto> GetById(int messageId)
    {
        var result = await _dbContext.Messages
            .Include(x => x.FileNames)
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.Id == messageId);
        var mappedResult = _mapper.Map<MessageDto>(result);
        return mappedResult;
    }

    public async Task<MessageDto> GetByCode(Guid code)
    {
        var result = await _dbContext.Messages
            .Include(x => x.FileNames)
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.Code == code.ToString());
        
        var mappedResult = _mapper.Map<MessageDto>(result);
        return mappedResult;
    }

    public async Task Update(MessageDto messageDto)
    {
        var message = await GetById(messageDto.Id);
        message.Text = messageDto.Text;
        message.FileNames = messageDto.FileNames;

        var a = _dbContext.Messages
            .Update(_mapper.Map<Message>(message));
        
        await _dbContext.SaveChangesAsync();
    }
}