using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using DramaLing.Api.Data;
using DramaLing.Api.Models.Entities;
using DramaLing.Api.Services;
using Microsoft.AspNetCore.Authorization;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

namespace DramaLing.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly DramaLingDbContext _context;
    private readonly IAuthService _authService;
    private readonly ILogger<AuthController> _logger;

    public AuthController(
        DramaLingDbContext context,
        IAuthService authService,
        ILogger<AuthController> logger)
    {
        _context = context;
        _authService = authService;
        _logger = logger;
    }

    [HttpPost("register")]
    public async Task<ActionResult> Register([FromBody] RegisterRequest request)
    {
        try
        {
            _logger.LogInformation("Registration attempt for user: {Username}, Email: {Email}",
                request.Username, request.Email);

            // 驗證請求
            if (!ModelState.IsValid)
            {
                _logger.LogWarning("Invalid model state for registration: {@ModelErrors}",
                    ModelState.Where(x => x.Value?.Errors.Count > 0)
                    .ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage)));
                return BadRequest(new { Success = false, Error = "Invalid request data" });
            }

            // 檢查Email是否已存在
            if (await _context.Users.AnyAsync(u => u.Email == request.Email))
                return BadRequest(new { Success = false, Error = "Email already exists" });

            // 檢查用戶名是否已存在
            if (await _context.Users.AnyAsync(u => u.Username == request.Username))
                return BadRequest(new { Success = false, Error = "Username already exists" });

            // 雜湊密碼
            var passwordHash = BCrypt.Net.BCrypt.HashPassword(request.Password);

            // 建立新用戶
            var user = new User
            {
                Id = Guid.NewGuid(),
                Username = request.Username,
                Email = request.Email,
                PasswordHash = passwordHash,
                DisplayName = request.Username, // 預設使用用戶名作為顯示名稱
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

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

            // 生成JWT Token
            var token = GenerateJwtToken(user);

            _logger.LogInformation("User registered successfully: {UserId}", user.Id);

            return Ok(new
            {
                Success = true,
                Data = new
                {
                    Token = token,
                    User = new
                    {
                        user.Id,
                        user.Username,
                        user.Email,
                        user.DisplayName,
                        user.AvatarUrl,
                        user.SubscriptionType
                    }
                }
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during user registration. Request: {@Request}", new {
                Username = request.Username,
                Email = request.Email,
                StackTrace = ex.StackTrace,
                InnerException = ex.InnerException?.Message
            });
            return StatusCode(500, new
            {
                Success = false,
                Error = "Registration failed",
                Details = ex.Message,
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpPost("login")]
    public async Task<ActionResult> Login([FromBody] LoginRequest request)
    {
        try
        {
            _logger.LogInformation("Login attempt for email: {Email}", request.Email);

            // 驗證請求
            if (!ModelState.IsValid)
            {
                _logger.LogWarning("Invalid model state for login: {@ModelErrors}",
                    ModelState.Where(x => x.Value?.Errors.Count > 0)
                    .ToDictionary(x => x.Key, x => x.Value?.Errors.Select(e => e.ErrorMessage)));
                return BadRequest(new { Success = false, Error = "Invalid request data" });
            }

            // 查找用戶
            var user = await _context.Users.FirstOrDefaultAsync(u => u.Email == request.Email);
            if (user == null)
                return Unauthorized(new { Success = false, Error = "Invalid email or password" });

            // 驗證密碼
            if (!BCrypt.Net.BCrypt.Verify(request.Password, user.PasswordHash))
                return Unauthorized(new { Success = false, Error = "Invalid email or password" });

            // 生成JWT Token
            var token = GenerateJwtToken(user);

            _logger.LogInformation("User logged in successfully: {UserId}", user.Id);

            return Ok(new
            {
                Success = true,
                Data = new
                {
                    Token = token,
                    User = new
                    {
                        user.Id,
                        user.Username,
                        user.Email,
                        user.DisplayName,
                        user.AvatarUrl,
                        user.SubscriptionType
                    }
                }
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during user login. Request: {@Request}", new {
                Email = request.Email,
                StackTrace = ex.StackTrace,
                InnerException = ex.InnerException?.Message
            });
            return StatusCode(500, new
            {
                Success = false,
                Error = "Login failed",
                Details = ex.Message,
                Timestamp = DateTime.UtcNow
            });
        }
    }

    private string GenerateJwtToken(User user)
    {
        var jwtSecret = Environment.GetEnvironmentVariable("DRAMALING_SUPABASE_JWT_SECRET")
            ?? Environment.GetEnvironmentVariable("DRAMALING_JWT_SECRET")
            ?? "dev-secret-minimum-32-characters-long-for-jwt-signing-in-development-mode-only";

        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.UTF8.GetBytes(jwtSecret);

        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim("sub", user.Id.ToString()),
                new Claim("email", user.Email),
                new Claim("username", user.Username),
                new Claim("name", user.DisplayName ?? user.Username)
            }),
            Expires = DateTime.UtcNow.AddDays(7),
            Issuer = Environment.GetEnvironmentVariable("DRAMALING_SUPABASE_URL") ?? "http://localhost:5000",
            Audience = "authenticated",
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256)
        };

        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }

    [HttpGet("profile")]
    [Authorize]
    public async Task<ActionResult> GetProfile()
    {
        try
        {
            var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
            if (userId == null)
                return Unauthorized(new { Success = false, Error = "Invalid token" });

            var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);

            // 如果用戶不存在，從 JWT 令牌建立基本資料
            if (user == null)
            {
                var claimsPrincipal = await _authService.ValidateTokenAsync(
                    Request.Headers.Authorization.ToString()["Bearer ".Length..].Trim());

                if (claimsPrincipal == null)
                    return Unauthorized(new { Success = false, Error = "Invalid token" });

                var email = claimsPrincipal.FindFirst("email")?.Value ?? "";
                var displayName = claimsPrincipal.FindFirst("name")?.Value ??
                                claimsPrincipal.FindFirst("user_metadata")?.Value ??
                                email.Split('@')[0];

                user = new User
                {
                    Id = userId.Value,
                    Email = email,
                    DisplayName = displayName,
                    SubscriptionType = "free"
                };

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

                _logger.LogInformation("Created new user profile for {UserId}", userId);
            }

            return Ok(new
            {
                Success = true,
                Data = new
                {
                    user.Id,
                    user.Email,
                    user.DisplayName,
                    user.AvatarUrl,
                    user.SubscriptionType,
                    user.CreatedAt
                }
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error fetching user profile");
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to fetch profile",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpPut("profile")]
    [Authorize]
    public async Task<ActionResult> UpdateProfile([FromBody] UpdateProfileRequest request)
    {
        try
        {
            var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
            if (userId == null)
                return Unauthorized(new { Success = false, Error = "Invalid token" });

            var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);
            if (user == null)
                return NotFound(new { Success = false, Error = "User not found" });

            // 更新用戶資料
            if (!string.IsNullOrWhiteSpace(request.DisplayName))
            {
                if (request.DisplayName.Length > 100)
                    return BadRequest(new { Success = false, Error = "Display name must be less than 100 characters" });

                user.DisplayName = request.DisplayName.Trim();
            }

            if (request.AvatarUrl != null)
                user.AvatarUrl = request.AvatarUrl?.Trim();

            if (request.Preferences != null)
                user.Preferences = request.Preferences;

            user.UpdatedAt = DateTime.UtcNow;
            await _context.SaveChangesAsync();

            return Ok(new
            {
                Success = true,
                Data = user,
                Message = "Profile updated successfully"
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error updating user profile");
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to update profile",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpGet("settings")]
    [Authorize]
    public async Task<ActionResult> GetSettings()
    {
        try
        {
            var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
            if (userId == null)
                return Unauthorized(new { Success = false, Error = "Invalid token" });

            var settings = await _context.UserSettings.FirstOrDefaultAsync(s => s.UserId == userId);

            // 如果沒有設定，建立預設設定
            if (settings == null)
            {
                settings = new UserSettings
                {
                    Id = Guid.NewGuid(),
                    UserId = userId.Value,
                    DailyGoal = 20,
                    ReminderTime = new TimeOnly(9, 0),
                    ReminderEnabled = true,
                    DifficultyPreference = "balanced",
                    AutoPlayAudio = true,
                    ShowPronunciation = true
                };

                _context.UserSettings.Add(settings);
                await _context.SaveChangesAsync();

                _logger.LogInformation("Created default settings for user {UserId}", userId);
            }

            return Ok(new
            {
                Success = true,
                Data = settings
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error fetching user settings");
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to fetch settings",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpPut("settings")]
    [Authorize]
    public async Task<ActionResult> UpdateSettings([FromBody] UpdateSettingsRequest request)
    {
        try
        {
            var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
            if (userId == null)
                return Unauthorized(new { Success = false, Error = "Invalid token" });

            var settings = await _context.UserSettings.FirstOrDefaultAsync(s => s.UserId == userId);
            if (settings == null)
                return NotFound(new { Success = false, Error = "Settings not found" });

            // 驗證並更新設定
            if (request.DailyGoal.HasValue)
            {
                if (request.DailyGoal < 1 || request.DailyGoal > 100)
                    return BadRequest(new { Success = false, Error = "Daily goal must be between 1 and 100" });

                settings.DailyGoal = request.DailyGoal.Value;
            }

            if (request.ReminderTime.HasValue)
                settings.ReminderTime = request.ReminderTime.Value;

            if (request.ReminderEnabled.HasValue)
                settings.ReminderEnabled = request.ReminderEnabled.Value;

            if (!string.IsNullOrEmpty(request.DifficultyPreference))
            {
                if (!new[] { "conservative", "balanced", "aggressive" }.Contains(request.DifficultyPreference))
                    return BadRequest(new { Success = false, Error = "Invalid difficulty preference" });

                settings.DifficultyPreference = request.DifficultyPreference;
            }

            if (request.AutoPlayAudio.HasValue)
                settings.AutoPlayAudio = request.AutoPlayAudio.Value;

            if (request.ShowPronunciation.HasValue)
                settings.ShowPronunciation = request.ShowPronunciation.Value;

            settings.UpdatedAt = DateTime.UtcNow;
            await _context.SaveChangesAsync();

            return Ok(new
            {
                Success = true,
                Data = settings,
                Message = "Settings updated successfully"
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error updating user settings");
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to update settings",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    /// <summary>
    /// 檢查用戶認證狀態 (無需資料庫查詢的快速檢查)
    /// </summary>
    [HttpGet("status")]
    [Authorize]
    public async Task<ActionResult> GetAuthStatus()
    {
        try
        {
            var userId = await _authService.GetUserIdFromTokenAsync(Request.Headers.Authorization);
            if (userId == null)
                return Unauthorized(new { Success = false, Error = "Invalid token" });

            return Ok(new
            {
                Success = true,
                Data = new
                {
                    IsAuthenticated = true,
                    UserId = userId,
                    Timestamp = DateTime.UtcNow
                }
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error checking auth status");
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to check auth status",
                Timestamp = DateTime.UtcNow
            });
        }
    }
}

// Request DTOs
public class RegisterRequest
{
    [Required(ErrorMessage = "Username is required")]
    [StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters")]
    public string Username { get; set; } = string.Empty;

    [Required(ErrorMessage = "Email is required")]
    [EmailAddress(ErrorMessage = "Invalid email format")]
    public string Email { get; set; } = string.Empty;

    [Required(ErrorMessage = "Password is required")]
    [StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be at least 8 characters")]
    public string Password { get; set; } = string.Empty;
}

public class LoginRequest
{
    [Required(ErrorMessage = "Email is required")]
    [EmailAddress(ErrorMessage = "Invalid email format")]
    public string Email { get; set; } = string.Empty;

    [Required(ErrorMessage = "Password is required")]
    public string Password { get; set; } = string.Empty;
}

public class UpdateProfileRequest
{
    public string? DisplayName { get; set; }
    public string? AvatarUrl { get; set; }
    public Dictionary<string, object>? Preferences { get; set; }
}

public class UpdateSettingsRequest
{
    public int? DailyGoal { get; set; }
    public TimeOnly? ReminderTime { get; set; }
    public bool? ReminderEnabled { get; set; }
    public string? DifficultyPreference { get; set; }
    public bool? AutoPlayAudio { get; set; }
    public bool? ShowPronunciation { get; set; }
}