using DataBase.Entities.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;
using MySqlConnector;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using User.Insight.Tracker.Common.Model;
using User.Insight.Tracker.DataContracts;
using User.Insight.Tracker.Services;

namespace User.Insight.Tracker.Common
{  
    [ExcludeFromCodeCoverage]
    public class ApiControllerBase : ControllerBase
    {
        public JwtTokenDetail CurrentUserJWT { get; private set; }

        // Existing constructor for backward compatibility
        public ApiControllerBase(IHttpContextAccessor httpContextAccessor)
        {
            var headerService = new JwtHeaderService();
            CurrentUserJWT = ExtractJwtToken(httpContextAccessor, headerService);
        }

        // New constructor with dependency injection
        public ApiControllerBase(IHttpContextAccessor httpContextAccessor, IJwtHeaderService headerService)
        {
            CurrentUserJWT = ExtractJwtToken(httpContextAccessor, headerService);
        }

        private JwtTokenDetail ExtractJwtToken(IHttpContextAccessor httpContextAccessor, IJwtHeaderService headerService)
        {
            var headers = headerService.GetHeaders(httpContextAccessor.HttpContext);

            var authHeader = headers.Authorization;
            var RoleId = headers.RoleId;

            if (string.IsNullOrEmpty(authHeader))
                return null;

            var token = authHeader.Replace("Bearer ", "").Trim();
            var handler = new JwtSecurityTokenHandler();
            if (!handler.CanReadToken(token))
                return null;

            var jwtToken = handler.ReadJwtToken(token);

            var email = jwtToken.Claims.FirstOrDefault(c => c.Type == "email" || c.Type == "upn")?.Value;
            if (string.IsNullOrEmpty(email))
                throw new UnauthorisedException("Email or UPN claim not found in token.");

            var dbContext = httpContextAccessor.HttpContext.RequestServices.GetRequiredService<ComputraceqaContext>();

            if (!string.IsNullOrWhiteSpace(RoleId))
                GetUserDetails(email, dbContext, RoleId);

            // Check hard expiry
            var expUnix = jwtToken.Claims.FirstOrDefault(c => c.Type == "exp")?.Value;
            if (long.TryParse(expUnix, out long exp))
            {
                var expiryDate = DateTimeOffset.FromUnixTimeSeconds(exp).UtcDateTime;
                if (expiryDate < DateTime.UtcNow)
                    throw new UnauthorisedException("Token has expired.");
            }

            // Check idle timeout using model bound header
            var lastActivityHeader = headers.XLastActivity;
            if (DateTime.TryParse(lastActivityHeader, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime lastActivityTime) &&
                DateTime.UtcNow > lastActivityTime.AddSeconds(Constant.TokenExpiry))
            {
                throw new UnauthorisedException("Token expired due to inactivity.");
            }

            return new JwtTokenDetail
            {
                Email = email,
                IssuedAt = DateTime.UtcNow
            };
        }

        [ExcludeFromCodeCoverage]
        private static void GetUserDetails(string email, ComputraceqaContext _dbContext, string roleId)
        {
            if (string.IsNullOrWhiteSpace(email))
                throw new ArgumentException("Email cannot be null or empty.", nameof(email));

            var user = _dbContext.AllUsers
                .FromSqlRaw("CALL GetUserExistDetails(@p_User_Email)",
                    new MySqlParameter("@p_User_Email", email))
                .AsEnumerable()
                .FirstOrDefault()
                ?? throw new UnauthorisedException("You are not Authorized.");

            if (!string.Equals(user.user_role_id.ToString()?.Trim(), roleId, StringComparison.OrdinalIgnoreCase))
                throw new RoleChangedException("Role Changed. Please Re-Login", 498);

            if (user.is_deleted == 1)
                throw new RoleChangedException("User has been deleted. Please contact the administrator.", 499);

            if (user.is_active != 1)
                throw new RoleChangedException("User Status changed to Inactive. Please contact the administrator.", 497);
        }
    }
}