using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Security.Cryptography;
using watcher_monitoring.Data;
using watcher_monitoring.Models;
using BCrypt.Net;

namespace watcher_monitoring.Controllers;

[Authorize]
[Route("[controller]")]
public class UserController : Controller
{
    private readonly WatcherDbContext _context;
    private readonly ILogger<UserController> _logger;

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

    // GET: /User

    public async Task<IActionResult> Index()
    {
        var users = await _context.Users
            .Include(u => u.ApiKeys)
            .OrderByDescending(u => u.CreatedAt)
            .ToListAsync();

        return View(users);
    }

    // GET: /User/Details/{id}
    [HttpGet("Details/{id}")]
    public async Task<IActionResult> Details(int id)
    {
        var user = await _context.Users
            .Include(u => u.ApiKeys)
            .FirstOrDefaultAsync(u => u.Id == id);

        if (user == null)
        {
            return NotFound();
        }

        return View(user);
    }

    // GET: /User/Create
    [HttpGet("Create")]
    public IActionResult Create()
    {
        return View();
    }

    // POST: /User/Create
    [HttpPost("Create")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("Username,Email,Password")] User user)
    {
        if (ModelState.IsValid)
        {
            // Prüfen, ob Username oder Email bereits existiert
            var existingUser = await _context.Users
                .FirstOrDefaultAsync(u => u.Username == user.Username || u.Email == user.Email);

            if (existingUser != null)
            {
                if (existingUser.Username == user.Username)
                {
                    ModelState.AddModelError("Username", "Benutzername ist bereits vergeben");
                }
                if (existingUser.Email == user.Email)
                {
                    ModelState.AddModelError("Email", "E-Mail-Adresse ist bereits registriert");
                }
                return View(user);
            }

            // Passwort hashen mit BCrypt
            user.Password = BCrypt.Net.BCrypt.HashPassword(user.Password);
            user.CreatedAt = DateTime.UtcNow;
            user.LastLogin = DateTime.UtcNow;
            user.IsActive = true;

            _context.Users.Add(user);
            await _context.SaveChangesAsync();

            _logger.LogInformation("Neuer User erstellt: {Username}", user.Username);

            return RedirectToAction(nameof(Index));
        }

        return View(user);
    }

    // GET: /User/Edit/{id}
    [HttpGet("Edit/{id}")]
    public async Task<IActionResult> Edit(int id)
    {
        var user = await _context.Users.FindAsync(id);
        if (user == null)
        {
            return NotFound();
        }

        return View(user);
    }

    // POST: /User/Edit/{id}
    [HttpPost("Edit/{id}")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, [Bind("Id,Username,Email,IsActive")] User updatedUser)
    {
        if (id != updatedUser.Id)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            try
            {
                var user = await _context.Users.FindAsync(id);
                if (user == null)
                {
                    return NotFound();
                }

                // Prüfen, ob neuer Username oder Email bereits von anderem User verwendet wird
                var duplicate = await _context.Users
                    .FirstOrDefaultAsync(u => u.Id != id && (u.Username == updatedUser.Username || u.Email == updatedUser.Email));

                if (duplicate != null)
                {
                    if (duplicate.Username == updatedUser.Username)
                    {
                        ModelState.AddModelError("Username", "Benutzername ist bereits vergeben");
                    }
                    if (duplicate.Email == updatedUser.Email)
                    {
                        ModelState.AddModelError("Email", "E-Mail-Adresse ist bereits registriert");
                    }
                    return View(updatedUser);
                }

                user.Username = updatedUser.Username;
                user.Email = updatedUser.Email;
                user.IsActive = updatedUser.IsActive;

                _context.Update(user);
                await _context.SaveChangesAsync();

                _logger.LogInformation("User aktualisiert: {Username}", user.Username);

                return RedirectToAction(nameof(Index));
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!await UserExists(updatedUser.Id))
                {
                    return NotFound();
                }
                throw;
            }
        }

        return View(updatedUser);
    }

    // POST: /User/Delete/{id}
    [HttpPost("Delete/{id}")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Delete(int id)
    {
        var user = await _context.Users
            .Include(u => u.ApiKeys)
            .FirstOrDefaultAsync(u => u.Id == id);

        if (user == null)
        {
            return NotFound();
        }

        // Alle API-Keys des Users löschen
        _context.ApiKeys.RemoveRange(user.ApiKeys);
        _context.Users.Remove(user);
        await _context.SaveChangesAsync();

        _logger.LogInformation("User gelöscht: {Username}", user.Username);

        return RedirectToAction(nameof(Index));
    }

    // POST: /User/ToggleActive/{id}
    [HttpPost("ToggleActive/{id}")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ToggleActive(int id)
    {
        var user = await _context.Users.FindAsync(id);
        if (user == null)
        {
            return NotFound();
        }

        user.IsActive = !user.IsActive;
        await _context.SaveChangesAsync();

        _logger.LogInformation("User {Username} wurde {Status}", user.Username, user.IsActive ? "aktiviert" : "deaktiviert");

        return RedirectToAction(nameof(Details), new { id });
    }

    // POST: /User/GenerateApiKey/{id}
    [HttpPost("GenerateApiKey/{id}")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> GenerateApiKey(int id, string keyName, string? description, DateTime? expiresAt)
    {
        var user = await _context.Users.FindAsync(id);
        if (user == null)
        {
            return NotFound();
        }

        if (string.IsNullOrWhiteSpace(keyName))
        {
            TempData["Error"] = "API-Key-Name ist erforderlich";
            return RedirectToAction(nameof(Details), new { id });
        }

        var apiKey = new ApiKey
        {
            Key = GenerateApiKeyString(),
            Name = keyName,
            Description = description,
            ExpiresAt = expiresAt,
            IsActive = true,
            UserId = user.Id
        };

        _context.ApiKeys.Add(apiKey);
        await _context.SaveChangesAsync();

        _logger.LogInformation("Neuer API-Key für User {Username} erstellt: {KeyName}", user.Username, keyName);

        TempData["Success"] = $"API-Key erstellt: {apiKey.Key}";
        TempData["NewApiKey"] = apiKey.Key;

        return RedirectToAction(nameof(Details), new { id });
    }

    // POST: /User/DeleteApiKey/{userId}/{keyId}
    [HttpPost("DeleteApiKey/{userId}/{keyId}")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteApiKey(int userId, int keyId)
    {
        var apiKey = await _context.ApiKeys
            .FirstOrDefaultAsync(k => k.Id == keyId && k.UserId == userId);

        if (apiKey == null)
        {
            return NotFound();
        }

        _context.ApiKeys.Remove(apiKey);
        await _context.SaveChangesAsync();

        _logger.LogInformation("API-Key gelöscht: {KeyName}", apiKey.Name);

        TempData["Success"] = "API-Key erfolgreich gelöscht";

        return RedirectToAction(nameof(Details), new { id = userId });
    }

    // POST: /User/ToggleApiKey/{userId}/{keyId}
    [HttpPost("ToggleApiKey/{userId}/{keyId}")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ToggleApiKey(int userId, int keyId)
    {
        var apiKey = await _context.ApiKeys
            .FirstOrDefaultAsync(k => k.Id == keyId && k.UserId == userId);

        if (apiKey == null)
        {
            return NotFound();
        }

        apiKey.IsActive = !apiKey.IsActive;
        await _context.SaveChangesAsync();

        _logger.LogInformation("API-Key {KeyName} wurde {Status}", apiKey.Name, apiKey.IsActive ? "aktiviert" : "deaktiviert");

        return RedirectToAction(nameof(Details), new { id = userId });
    }

    private async Task<bool> UserExists(int id)
    {
        return await _context.Users.AnyAsync(u => u.Id == id);
    }

    private static string GenerateApiKeyString()
    {
        var randomBytes = new byte[32];
        using var rng = RandomNumberGenerator.Create();
        rng.GetBytes(randomBytes);
        return Convert.ToBase64String(randomBytes).Replace("+", "").Replace("/", "").Replace("=", "");
    }
}
