 using System.Diagnostics;
 using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

using watcher_monitoring.Models;
using watcher_monitoring.Data;
using watcher_monitoring.Attributes;
using watcher_monitoring.Payloads;
using System.Net;



namespace watcher_monitoring.Controllers;

[ApiController]
[Route("[controller]")]
[ApiKeyAuth]
public class APIController : Controller
{
    private readonly WatcherDbContext _context;

    private readonly ILogger<APIController> _logger;

    public APIController(WatcherDbContext context, ILogger<APIController> logger)
    {
        _context = context;
        _logger = logger;
    }

    // API Calls

    [HttpGet("get-server")]
    public async Task<IActionResult> Servers()
    {
        List<Server> servers = await _context.Servers.ToListAsync();
        return Ok(servers);
    }

    // DEVELOPMENT ONLY
    [HttpPost("add-server")]
    public async Task<IActionResult> AddServer([FromBody] Server serverDto)
    {
        // payload check
        if (!ModelState.IsValid)
        {
            var errors = ModelState.Values
                .SelectMany(v => v.Errors)
                .Select(e => e.ErrorMessage)
                .ToList();

            _logger.LogError("Invalid server payload");
            return BadRequest(new { error = "Invalid server payload", details = errors });
        }

        try
        {
            // Check if server with same IP already exists
            var existingServer = await _context.Servers
                .FirstOrDefaultAsync(s => s.IPAddress == serverDto.IPAddress);

            if (existingServer != null)
            {
                _logger.LogWarning("Server mit IP-Adresse {ip} existiert bereits", serverDto.IPAddress);
                return BadRequest(new { error = "Server mit dieser IP-Adresse existiert bereits" });
            }

            Server server = new Server
            {
                Name = serverDto.Name,
                IPAddress = serverDto.IPAddress,
                CpuType = serverDto.CpuType,
                CpuCores = serverDto.CpuCores,
                GpuType = serverDto.GpuType,
                RamSize = serverDto.RamSize,
                DiskSpace = serverDto.DiskSpace,
                State = serverDto.State,
                IsVerified = serverDto.IsVerified
            };

            _context.Servers.Add(server);
            await _context.SaveChangesAsync();

            _logger.LogInformation("Server '{name}' mit IP {ip} erfolgreich hinzugefügt", server.Name, server.IPAddress);

            return Ok(new { message = "Server erfolgreich hinzugefügt", serverId = server.Id });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Fehler beim Hinzufügen des Servers");
            return BadRequest(new { error = "Fehler beim Hinzufügen des Servers", details = ex.Message });
        }
    }

    [HttpDelete("delete-server/{id}")]
    public async Task<IActionResult> DeleteServer(int id)
    {
        var server = await _context.Servers.FindAsync(id);
        if (server == null)
        {
            _logger.LogError("Server nicht gefunden");
            return BadRequest();
        }

        _context.Servers.Remove(server);
        await _context.SaveChangesAsync();

        _logger.LogInformation("Server '{server}' erfolgreich gelöscht", server.Name);


        return Ok();
    }

    [HttpPut("edit-server")]
    public async Task<IActionResult> EditServer()
    {
        return Ok();
    }

    // Container Calls
    [HttpGet("get-container")]
    public async Task<IActionResult> Containers()
    {
        List<Container> containers = await _context.Containers.ToListAsync();
        return Ok(containers);
    }

    [HttpDelete("delete-container")]
    public async Task<IActionResult> DeleteContainer(int id)
    {
        var container = await _context.Containers.FindAsync(id);
        if (container == null)
        {
            _logger.LogError("Server nicht gefunden");
            return BadRequest();
        }
        try
        {
            _context.Containers.Remove(container);
            await _context.SaveChangesAsync();
            _logger.LogInformation("Container '{container}' erfolgreich gelöscht", container.Id);
            return Ok();
        } catch (Exception ex)
        {
            _logger.LogError(ex.Message);
            return BadRequest();
        }
    }

    // Agent Calls

    // Registration Endpoint for watcher-agent
    [HttpPost("agent-register")]
    public async Task<IActionResult> Register([FromBody] RegistrationDto dto)
    {
        // payload check
        if (!ModelState.IsValid)
        {
            var errors = ModelState.Values
                .SelectMany(v => v.Errors)
                .Select(e => e.ErrorMessage)
                .ToList();

            _logger.LogError("Invalid registration payload");
            return BadRequest(new { error = "Invalid registration payload", details = errors });
        }

        try {
            Server newServer = new Server
            {
                Name = dto.hostName,
                IPAddress = dto.ipAddress
            };

            _context.Servers.Add(newServer);
            await _context.SaveChangesAsync();

            var server = await _context.Servers.FindAsync(dto.ipAddress);

            if (server != null)
            {
                return Ok(server.Id);
            } else
            {
                return BadRequest();
            }
             
        } catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            _logger.LogError(ex.Message);
            return BadRequest();
        }
    }

    // Hardware Configuration Endpoint for watcher-agent
    [HttpPost("agent-hardware")]
    public async Task<IActionResult> HardwareConfiguration ([FromBody] HardwareDto dto)
    {
        // payload check
        if (!ModelState.IsValid)
        {
            var errors = ModelState.Values
                .SelectMany(v => v.Errors)
                .Select(e => e.ErrorMessage)
                .ToList();

            _logger.LogError("Invalid hardware configuration");
            return BadRequest(new { error = "Invalid Hardware Configuration Payload", details = errors });
        }
        try
        {
            // Find Server in Database
            var server = await _context.Servers.FindAsync(dto.id);

            if (server == null)
            {
                _logger.LogError("Server not found");
                return BadRequest("Server not found");
            }

            // Add Hardware Configuration
            server.CpuType = dto.cpuType;
            server.CpuCores = dto.cpuCores;
            server.GpuType = dto.gpuType;
            server.RamSize = dto.ramSize;
            // TODO: Diskspace fehlt

            await _context.SaveChangesAsync();
            _logger.LogInformation("Harware configuration successfull for server {server}", server.Name);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message);
            return BadRequest(ex.Message);
        }


        return Ok();
    }

    // Server-Metrics endpoint for watcher-agent
    [HttpPost("agent-server-metrics/{id}")]
    public async Task<IActionResult> ServerMetrics ([FromBody] MetricDto dto)
    {
        if (!ModelState.IsValid)
        {
            var errors = ModelState.Values
                .SelectMany(v => v.Errors)
                .Select(e => e.ErrorMessage)
                .ToList();

            _logger.LogError("Invalid monitoring payload");
            return BadRequest(new { error = "Invalid monitoring payload", details = errors });
        }

        var server = await _context.Servers.FindAsync(dto.id);

        if (server != null)
        {
            // neues Objekt mit Typ Metric anlegen

            // Metric in Datenbank eintragen

            return Ok();
        }
        else
        {
            _logger.LogError("metric cannot be added to database");
            return BadRequest();
        }
    }

    // Service-Detection endpoint for watcher-agent
    [HttpPost("agent-container-detection")]
    public async Task<IActionResult> ContainerDetection ([FromBody] HardwareDto dto)
    {
        return Ok();
    }

    // Container-Metrics endpoint for watcher-agent
    [HttpPost("agent-container-metrics")]
    public async Task<IActionResult> ContainerMetrics ([FromBody] HardwareDto dto)
    {
        return Ok();
    }
}