using AquaCubeIT.Service.NetFloppy.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Sockets;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using RefreshRequest = AquaCubeIT.Service.NetFloppy.Models.RefreshRequest;

namespace AquaCubeIT.Service.NetFloppy.Controllers;

[ApiController]
[Route("[controller]")]
public class LogonController : ControllerBase
{
    private readonly IConfiguration _config;
    private readonly ILogger<LogonController> _logger;

    public LogonController(ILogger<LogonController> logger, IConfiguration config)
    {
        _config = config;
        _logger = logger;
    }

    [HttpGet]
    [Authorize]
    public async Task<string> Get()
    {
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        var email = User.FindFirstValue(ClaimTypes.Email);
        var roles = User.FindAll(ClaimTypes.Role).Select(c => c.Value).ToList();

        var allClaims = User.Claims.Select(c => c.Value).ToList();

        return $"User: {userId}, {email}, {string.Join(",", roles)}, {string.Join(",",allClaims)}";
    }

    private RefreshResponsePayload GenerateToken(RefreshRequestPayload request)
    {
        
        if (request.RefreshToken == null)
        {
            throw new BadHttpRequestException("Bad Payload");
        }

        // Hash incoming token the same way
        byte[] raw = Convert.FromBase64String(request.RefreshToken);
        string reqHash = Convert.ToHexString(SHA256.HashData(raw));

        // Get token by hash



        // Check family is ok

        string? family = null;
        var userName = "Test";

        // Check if revoked



        // Throw error if revoked or expired kill all family tokens



        // Save refresh token by hash

        // Check 
        return GenerateToken(userName, GenerateRefreshToken(family));
    }

    private string GenerateRefreshToken(string? family)
    {
        // Update refreshToken
        var bytes = RandomNumberGenerator.GetBytes(64);
        var refreshToken = Convert.ToBase64String(bytes);
        var hash = Convert.ToHexString(SHA256.HashData(bytes));
        family = family ?? Guid.NewGuid().ToString("N");

        // Save refresh token by hash

        return refreshToken;
    }

    private LogonResponsePayload GenerateToken(LogonRequestPayload request)
    {
        return GenerateToken(request.UserName, GenerateRefreshToken(null));
    }

    private RefreshResponsePayload GenerateToken(string? userName, string refreshToken)
    { 
        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, userName),     
            new Claim(ClaimTypes.Name, "Stephen Barriball"),
            new Claim(ClaimTypes.Role, "User")       
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var expiryDate = DateTime.Now.AddMinutes(15);
        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: expiryDate,
            signingCredentials: creds);
    
        // Return new token and refresh token
        return new RefreshResponsePayload() { Token = new JwtSecurityTokenHandler().WriteToken(token), RefreshToken = refreshToken, TokenExpiry = expiryDate };
    }


    [HttpPost]
    public async Task<LogonResponse> Post(LogonRequest request)
    {
        var response = new LogonResponse();

        if (request.Payload == null)
        {
            throw new Exception("Invalid Payload");
        }

        // Validate user here
        if (request.Payload.UserName == "test" && request.Payload.Password == "password")
        {            
            response.Payload = GenerateToken(request.Payload);          
            response.Success = true;
        }
        else
        {
            response.Success = false;
            response.Error = new ErrorResponsePayload() { ErrorNo = 15, Message = "Invalid Login" };
        }

        return response;
    }

    [HttpPost("refresh")]
    public async Task<RefreshResponse> Refresh(RefreshRequest request)
    {
        try
        {
            if (request.Payload == null)
            {
                throw new BadHttpRequestException("Invalid Payload");
            }

            // Hash incoming token the same way
            byte[] raw = Convert.FromBase64String(request.Payload.RefreshToken);
            string reqHash = Convert.ToHexString(SHA256.HashData(raw));

            //var stored = await _repo.GetRefreshTokenByHashAsync(reqHash);

            //if (stored is null || stored.RevokedAtUtc != null || stored.ExpiresAtUtc < DateTime.UtcNow)
            //{
            //    throw new UnauthorizedAccessException();
            //return Unauthorized();
            //}

            // Rotate: revoke old, issue new pair in same family
            //stored.RevokedAtUtc = DateTime.UtcNow;

            //var user = await _users.GetByIdAsync(stored.UserId);

            return new RefreshResponse() { Payload = GenerateToken(request.Payload), Success = true };
        }
        catch(Exception e)
        {
            return new RefreshResponse() { Success = false, Error = new ErrorResponsePayload() { Exception = e, Message = e.Message, ErrorNo = 14 } };
        }
    }
}
