using System.Net;
using adas_core.Application.Exceptions;
using adas_core.Application.Services.Interfaces;
using adas_core.Authentication.Attributes;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Utils;
using adas_core.Logging;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MongoDB.Bson;

namespace adas_core.Controllers;

[ApiController]
[Route("Relay")]
public class RelayController : ControllerBase
{
    // TODO: ver donde ses usa este controlador para version 3 del modelo

    private string? _url = string.Empty;
    private readonly IPointOfCareService _pointOfCareService;
    private readonly IRelayService _relayService;
    private readonly ILogger<RelayController> _logger;
    
    public RelayController(
        IOptions<RecordingSettings> recordingSettings, 
        IRelayService relayService, 
        ILogger<RelayController> logger, IPointOfCareService pointOfCareService)
    {
        LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
    
        _relayService = relayService;
        _logger = logger;
        _pointOfCareService = pointOfCareService;
    }
    
    
    [HttpGet]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [Route("status")]
    public async Task<IActionResult> CheckSectionStatus()
    {
        var section = await _pointOfCareService.GetAllConfigs();
        if (section.IsNullOrEmpty()) return NotFound();
        var boxes = section.Where(b =>b.Configuration != null && !b.Configuration.RelayList.IsNullOrEmpty()).ToList();
        var dict = new List<object>();
        foreach (var box in boxes)
        {
            foreach (var relay in box.Configuration!.RelayList!)
            {
                var status = await _relayService.CheckRelayStatus(relay);
                dict.Add(new { Unit = box.Unit?.Name??box.UnitId.ToString(), bed = box.Bed, status});  
            }
        }
    
        return Ok(dict);
    }
    
    
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [Route("powerOn")]
    public async Task<IActionResult> PowerOnPoC([FromBody] PowerActionRequest action)
    {
        return await PowerAction(action.UnitId, action.PointOfCareId, action.Bed, async (relayConfig) =>
        {
            await _relayService.PowerOn(relayConfig);
        });
    }
    
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [Route("powerOff")]
    public async Task<IActionResult> PowerOffPoC([FromBody] PowerActionRequest action)
    {
        return await PowerAction(action.UnitId, action.PointOfCareId, action.Bed, async (relayConfig) =>
        {
            await _relayService.PowerOff(relayConfig);
        });
    }
    
    private async Task<IActionResult> PowerAction(string unitId, string pointOfCareId, string bed, Func<Relay, Task> action)
    {
        if(!ObjectId.TryParse(pointOfCareId, out var poc)) return Conflict("Cannot parse to OBjectId");

        var box = await _pointOfCareService.FindByIdAllConfig(poc);
        if (box == null) return NotFound("No box found");
    
        if (box.Configuration == null || box.Configuration.RelayList.IsNullOrEmpty()) return NotFound("No relay configuration found");

        foreach (var relay in box.Configuration.RelayList!)
        {
            await action(relay);
        }
    
        return Ok();
    }
    
    
    
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthAdmin)]
    [Route("{id}/status")]
    public IActionResult CheckRelayStatus(int id, string driver, string host, int port, string relayName, int total, string username, string password)
    {
        Relay relayConfig = new()
        {
            Driver = driver,
            Ip = host,
            Port = port,
            RelayNumber = id,
            RelayName = relayName,
            Total = total,
            Username = username,
            Password = password
        };
        var strConfig = relayConfig.ToString() ?? "null";            
        _logger.LogDebug("Config:{strConfig}", strConfig);
    
        var result = _relayService.CheckRelayStatus(relayConfig);
    
        var resultStr = result.ToString()??"null";
        _logger.LogDebug("Relay Status {resultStr}", resultStr);
    
        return Ok(result);
    }
    
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [Route("{id}/power/on")]
    public IActionResult PowerOn(int id, string driver, string host, int port, string relayName, int total, string username, string? password)
    {
        Relay relayConfig = new()
        {
            Driver = driver,
            Ip = host,
            Port = port,
            RelayNumber = id,
            RelayName = relayName,
            Total = total,
            Username = username,
            Password = password
        };
    
        var strConfig = relayConfig.ToString() ?? "null";
        _logger.LogDebug("Config: {strConfig}", strConfig);
    
    
        try
        {
            _relayService.PowerOn(relayConfig);
        }
        catch (Exception)
        {
            return StatusCode(int.Parse(HttpStatusCode.InternalServerError.ToString()));
    
        }
    
    
        return Ok(true);
    }
    
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [Route("{id}/power/off")]
    public IActionResult PowerOff(int id, string driver, string host, int port, string relayName, int total, string username, string? password)
    {
        Relay relayConfig = new ()
        {
            Driver = driver,
            Ip = host,
            Port = port,
            RelayNumber = id,
            RelayName = relayName,
            Total = total,
            Username = username,
            Password = password
        };
    
        var strConfig = relayConfig.ToString() ?? "null";
        _logger.LogDebug("Config: {strConfig}", strConfig);
    
        try
        {
            _relayService.PowerOff(relayConfig);
        }
        catch (Exception)
        {
            return StatusCode(int.Parse(HttpStatusCode.InternalServerError.ToString()));
        }
        return Ok(false);
    }
    
    
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [Route("manual/{status}")]
    public  IActionResult ManualSwitch(string status, string pocId, string type)
    {
        try
        {
            if (!Enum.TryParse( status, out RelayEnum.Status relayStatus))
                return BadRequest();
            if (!Enum.TryParse( type, out RelayEnum.Type relayType))
                return BadRequest();
            if (!ObjectId.TryParse(pocId, out var poc))
                return BadRequest();
    
            _= _relayService.SetManualRelay( relayStatus, poc, relayType);
        }
        catch (Exception)
        {
            return StatusCode(int.Parse(HttpStatusCode.InternalServerError.ToString()));
        }
        return Ok(false);
    }
    [HttpPost("paginated")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> GetPaginatedUnits([FromBody] PaginationFilter request, bool withPoCs)
    {
        if (request == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        var relays = await _relayService.GetPaginatedRelays(request);
        return Ok(relays);
    }
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> CreateRelay([FromBody] Relay? request)
    {
        if (request == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        var relays = await _relayService.InsertRelay(request);
        return Ok(relays);
    }
    [HttpPut("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> UpdateRelay([FromBody] Relay relay, string id)
    {
        if (!ObjectId.TryParse(id, out var idParsed)) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        var relayUpdated = await _relayService.UpdateRelayById(idParsed, relay);
        return Ok(relayUpdated);
    }
    
}

public class PowerActionRequest
{
    public string UnitId { get; set; } = null!;
    public string PointOfCareId { get; set; } = null!;
    public string Bed { get; set; } = null!;
}