using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using API.Constants;
using API.Data;
using API.Data.Repositories;
using API.DTOs.Dashboard;
using API.DTOs.Filtering.v2;
using API.Entities;
using API.Extensions;
using API.Helpers;
using API.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace API.Controllers;
#nullable enable
/// 
/// This is responsible for Filter caching
/// 
public class FilterController : BaseApiController
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly ILocalizationService _localizationService;
    private readonly IStreamService _streamService;
    private readonly ILogger _logger;
    public FilterController(IUnitOfWork unitOfWork, ILocalizationService localizationService, IStreamService streamService,
        ILogger logger)
    {
        _unitOfWork = unitOfWork;
        _localizationService = localizationService;
        _streamService = streamService;
        _logger = logger;
    }
    /// 
    /// Creates or Updates the filter
    /// 
    /// 
    /// 
    [HttpPost("update")]
    public async Task CreateOrUpdateSmartFilter(FilterV2Dto dto)
    {
        var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.SmartFilters);
        if (user == null) return Unauthorized();
        if (User.IsInRole(PolicyConstants.ReadOnlyRole)) return BadRequest(await _localizationService.Translate(User.GetUserId(), "permission-denied"));
        if (string.IsNullOrWhiteSpace(dto.Name)) return BadRequest("Name must be set");
        if (Seed.DefaultStreams.Any(s => s.Name.Equals(dto.Name, StringComparison.InvariantCultureIgnoreCase)))
        {
            return BadRequest("You cannot use the name of a system provided stream");
        }
        var existingFilter =
            user.SmartFilters.FirstOrDefault(f => f.Name.Equals(dto.Name, StringComparison.InvariantCultureIgnoreCase));
        if (existingFilter != null)
        {
            // Update the filter
            existingFilter.Filter = SmartFilterHelper.Encode(dto);
            _unitOfWork.AppUserSmartFilterRepository.Update(existingFilter);
        }
        else
        {
            existingFilter = new AppUserSmartFilter()
            {
                Name = dto.Name,
                Filter = SmartFilterHelper.Encode(dto)
            };
            user.SmartFilters.Add(existingFilter);
            _unitOfWork.UserRepository.Update(user);
        }
        if (!_unitOfWork.HasChanges()) return Ok();
        await _unitOfWork.CommitAsync();
        return Ok();
    }
    [HttpGet]
    public ActionResult> GetFilters()
    {
        return Ok(_unitOfWork.AppUserSmartFilterRepository.GetAllDtosByUserId(User.GetUserId()));
    }
    [HttpDelete]
    public async Task DeleteFilter(int filterId)
    {
        if (User.IsInRole(PolicyConstants.ReadOnlyRole)) return BadRequest(await _localizationService.Translate(User.GetUserId(), "permission-denied"));
        var filter = await _unitOfWork.AppUserSmartFilterRepository.GetById(filterId);
        if (filter == null) return Ok();
        // This needs to delete any dashboard filters that have it too
        var streams = await _unitOfWork.UserRepository.GetDashboardStreamWithFilter(filter.Id);
        _unitOfWork.UserRepository.Delete(streams);
        var streams2 = await _unitOfWork.UserRepository.GetSideNavStreamWithFilter(filter.Id);
        _unitOfWork.UserRepository.Delete(streams2);
        _unitOfWork.AppUserSmartFilterRepository.Delete(filter);
        await _unitOfWork.CommitAsync();
        return Ok();
    }
    /// 
    /// Encode the Filter
    /// 
    /// 
    /// 
    [HttpPost("encode")]
    public ActionResult EncodeFilter(FilterV2Dto dto)
    {
        return Ok(SmartFilterHelper.Encode(dto));
    }
    /// 
    /// Decodes the Filter
    /// 
    /// 
    /// 
    [HttpPost("decode")]
    public ActionResult DecodeFilter(DecodeFilterDto dto)
    {
        return Ok(SmartFilterHelper.Decode(dto.EncodedFilter));
    }
    /// 
    /// Rename a Smart Filter given the filterId and new name
    /// 
    /// 
    /// 
    /// 
    [HttpPost("rename")]
    public async Task RenameFilter([FromQuery] int filterId, [FromQuery] string name)
    {
        try
        {
            var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(),
                AppUserIncludes.SmartFilters);
            if (user == null) return Unauthorized();
            name = name.Trim();
            if (User.IsInRole(PolicyConstants.ReadOnlyRole))
            {
                return BadRequest(await _localizationService.Translate(user.Id, "permission-denied"));
            }
            if (string.IsNullOrWhiteSpace(name))
            {
                return BadRequest(await _localizationService.Translate(user.Id, "smart-filter-name-required"));
            }
            if (Seed.DefaultStreams.Any(s => s.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)))
            {
                return BadRequest(await _localizationService.Translate(user.Id, "smart-filter-system-name"));
            }
            var filter = user.SmartFilters.FirstOrDefault(f => f.Id == filterId);
            if (filter == null)
            {
                return BadRequest(await _localizationService.Translate(user.Id, "filter-not-found"));
            }
            filter.Name = name;
            _unitOfWork.AppUserSmartFilterRepository.Update(filter);
            await _unitOfWork.CommitAsync();
            await _streamService.RenameSmartFilterStreams(filter);
            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "There was an exception when renaming smart filter: {FilterId}", filterId);
            return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-error"));
        }
    }
}