using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Haoliang.Core.Services;
using Haoliang.Models.User;
using Haoliang.Models.Common;

namespace Haoliang.Api.Controllers
{
    [ApiController]
    [Route("api/v1/[controller]")]
    public class AuthController : ControllerBase
    {
        private readonly IAuthService _authService;
        private readonly IUserService _userService;
        private readonly IPermissionService _permissionService;
        private readonly ILoggingService _loggingService;

        public AuthController(
            IAuthService authService,
            IUserService userService,
            IPermissionService permissionService,
            ILoggingService loggingService)
        {
            _authService = authService;
            _userService = userService;
            _permissionService = permissionService;
            _loggingService = loggingService;
        }

        [HttpPost("login")]
        public async Task<IActionResult> Login([FromBody] LoginRequest request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ApiResponse<AuthResult>.Error("Invalid request data", 400));
                }

                var result = await _authService.LoginAsync(request);
                
                if (result.Success)
                {
                    await _loggingService.LogInformationAsync($"User {request.Username} logged in successfully");
                    return Ok(ApiResponse<AuthResult>.Success(result));
                }
                else
                {
                    await _loggingService.LogWarningAsync($"Failed login attempt for user {request.Username}");
                    return Unauthorized(ApiResponse<AuthResult>.Error("Invalid username or password", 401));
                }
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Login error for user {request.Username}: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<AuthResult>.Error("Internal server error", 500));
            }
        }

        [HttpPost("logout")]
        public async Task<IActionResult> Logout([FromBody] LogoutRequest request)
        {
            try
            {
                if (request?.UserId == null)
                {
                    return BadRequest(ApiResponse<bool>.Error("User ID is required", 400));
                }

                var success = await _authService.LogoutAsync(request.UserId.Value);
                
                if (success)
                {
                    await _loggingService.LogInformationAsync($"User {request.UserId} logged out successfully");
                    return Ok(ApiResponse<bool>.Success(true));
                }
                else
                {
                    return BadRequest(ApiResponse<bool>.Error("Logout failed", 400));
                }
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Logout error: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
            }
        }

        [HttpPost("refresh")]
        public async Task<IActionResult> RefreshToken([FromBody] RefreshTokenRequest request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ApiResponse<AuthResult>.Error("Invalid request data", 400));
                }

                var result = await _authService.RefreshTokenAsync(request.RefreshToken);
                
                if (result.Success)
                {
                    return Ok(ApiResponse<AuthResult>.Success(result));
                }
                else
                {
                    return Unauthorized(ApiResponse<AuthResult>.Error("Invalid refresh token", 401));
                }
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Token refresh error: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<AuthResult>.Error("Internal server error", 500));
            }
        }

        [HttpPost("register")]
        public async Task<IActionResult> Register([FromBody] RegisterRequest request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ApiResponse<UserViewModel>.Error("Invalid request data", 400));
                }

                // Check if username already exists
                var usernameExists = await _authService.UsernameExistsAsync(request.Username);
                if (usernameExists)
                {
                    return BadRequest(ApiResponse<UserViewModel>.Error("Username already exists", 400));
                }

                // Check if email already exists
                var emailExists = await _authService.EmailExistsAsync(request.Email);
                if (emailExists)
                {
                    return BadRequest(ApiResponse<UserViewModel>.Error("Email already exists", 400));
                }

                // Create user
                var user = new User
                {
                    Username = request.Username,
                    Email = request.Email,
                    PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password),
                    FirstName = request.FirstName,
                    LastName = request.LastName,
                    Department = request.Department,
                    IsActive = true,
                    CreatedAt = DateTime.Now,
                    UpdatedAt = DateTime.Now
                };

                var userViewModel = await _userService.CreateUserAsync(user);
                
                await _loggingService.LogInformationAsync($"New user registered: {request.Username}");
                return Ok(ApiResponse<UserViewModel>.Success(userViewModel));
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Registration error for user {request.Username}: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
            }
        }

        [HttpGet("profile")]
        public async Task<IActionResult> GetProfile()
        {
            try
            {
                // Get user ID from claims (in real implementation, use JWT token validation)
                var userId = GetCurrentUserId();
                if (userId == null)
                {
                    return Unauthorized(ApiResponse<UserViewModel>.Error("Not authenticated", 401));
                }

                var user = await _userService.GetUserByIdAsync(userId.Value);
                if (user == null)
                {
                    return NotFound(ApiResponse<UserViewModel>.Error("User not found", 404));
                }

                return Ok(ApiResponse<UserViewModel>.Success(user));
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Profile fetch error: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
            }
        }

        [HttpPut("profile")]
        public async Task<IActionResult> UpdateProfile([FromBody] UpdateUserProfileRequest request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ApiResponse<UserViewModel>.Error("Invalid request data", 400));
                }

                var userId = GetCurrentUserId();
                if (userId == null)
                {
                    return Unauthorized(ApiResponse<UserViewModel>.Error("Not authenticated", 401));
                }

                var user = new User
                {
                    Username = request.Username,
                    Email = request.Email,
                    FirstName = request.FirstName,
                    LastName = request.LastName,
                    Department = request.Department,
                    UpdatedAt = DateTime.Now
                };

                var updatedUser = await _userService.UpdateUserAsync(userId.Value, user);
                
                await _loggingService.LogInformationAsync($"User profile updated: {request.Username}");
                return Ok(ApiResponse<UserViewModel>.Success(updatedUser));
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Profile update error: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
            }
        }

        [HttpPost("change-password")]
        public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequest request)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ApiResponse<bool>.Error("Invalid request data", 400));
                }

                var userId = GetCurrentUserId();
                if (userId == null)
                {
                    return Unauthorized(ApiResponse<bool>.Error("Not authenticated", 401));
                }

                var success = await _userService.ChangePasswordAsync(
                    userId.Value, 
                    request.OldPassword, 
                    request.NewPassword);

                if (success)
                {
                    await _loggingService.LogInformationAsync($"Password changed for user: {userId}");
                    return Ok(ApiResponse<bool>.Success(true));
                }
                else
                {
                    return BadRequest(ApiResponse<bool>.Error("Invalid old password", 400));
                }
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Password change error: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
            }
        }

        [HttpGet("permissions")]
        public async Task<IActionResult> GetUserPermissions()
        {
            try
            {
                var userId = GetCurrentUserId();
                if (userId == null)
                {
                    return Unauthorized(ApiResponse<IEnumerable<string>>.Error("Not authenticated", 401));
                }

                var permissions = await _permissionService.GetUserPermissionsAsync(userId.Value);
                return Ok(ApiResponse<IEnumerable<string>>.Success(permissions));
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Permission fetch error: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<IEnumerable<string>>.Error("Internal server error", 500));
            }
        }

        [HttpGet("users")]
        [ProducesResponseType(typeof(PaginatedResponse<UserViewModel>), 200)]
        public async Task<IActionResult> GetAllUsers([FromQuery] UserFilter filter)
        {
            try
            {
                var users = await _userService.GetAllUsersAsync();
                
                // Apply filters
                if (!string.IsNullOrEmpty(filter.Role))
                {
                    users = users.Where(u => u.Role == filter.Role);
                }
                
                if (!string.IsNullOrEmpty(filter.Department))
                {
                    users = users.Where(u => u.Department == filter.Department);
                }

                if (filter.IsActive.HasValue)
                {
                    users = users.Where(u => u.IsActive == filter.IsActive.Value);
                }

                var totalCount = users.Count();
                
                // Apply pagination
                var pagedUsers = users
                    .Skip((filter.PageNumber - 1) * filter.PageSize)
                    .Take(filter.PageSize)
                    .ToList();

                var response = new PaginatedResponse<UserViewModel>
                {
                    Items = pagedUsers,
                    TotalCount = totalCount,
                    PageNumber = filter.PageNumber,
                    PageSize = filter.PageSize,
                    TotalPages = (int)Math.Ceiling((double)totalCount / filter.PageSize),
                    HasPreviousPage = filter.PageNumber > 1,
                    HasNextPage = filter.PageNumber < (int)Math.Ceiling((double)totalCount / filter.PageSize)
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Users fetch error: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<PaginatedResponse<UserViewModel>>.Error("Internal server error", 500));
            }
        }

        [HttpGet("users/{id}")]
        public async Task<IActionResult> GetUserById(int id)
        {
            try
            {
                var user = await _userService.GetUserByIdAsync(id);
                if (user == null)
                {
                    return NotFound(ApiResponse<UserViewModel>.Error("User not found", 404));
                }

                return Ok(ApiResponse<UserViewModel>.Success(user));
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"User fetch error for ID {id}: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
            }
        }

        [HttpPost("users/{id}/activate")]
        public async Task<IActionResult> ActivateUser(int id)
        {
            try
            {
                var success = await _userService.ActivateUserAsync(id);
                if (success)
                {
                    await _loggingService.LogInformationAsync($"User activated: {id}");
                    return Ok(ApiResponse<bool>.Success(true));
                }
                else
                {
                    return BadRequest(ApiResponse<bool>.Error("Failed to activate user", 400));
                }
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"User activation error for ID {id}: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
            }
        }

        [HttpPost("users/{id}/deactivate")]
        public async Task<IActionResult> DeactivateUser(int id)
        {
            try
            {
                var success = await _userService.DeactivateUserAsync(id);
                if (success)
                {
                    await _loggingService.LogInformationAsync($"User deactivated: {id}");
                    return Ok(ApiResponse<bool>.Success(true));
                }
                else
                {
                    return BadRequest(ApiResponse<bool>.Error("Failed to deactivate user", 400));
                }
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"User deactivation error for ID {id}: {ex.Message}", ex);
                return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
            }
        }

        private int? GetCurrentUserId()
        {
            // In a real implementation, extract user ID from JWT token claims
            // For now, return null (would be implemented in JWT middleware)
            return null;
        }
    }

    // Supporting request and response models
    public class LoginRequest
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public bool RememberMe { get; set; }
    }

    public class LogoutRequest
    {
        public int UserId { get; set; }
    }

    public class RefreshTokenRequest
    {
        public string RefreshToken { get; set; }
    }

    public class RegisterRequest
    {
        public string Username { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string ConfirmPassword { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Department { get; set; }
    }

    public class UpdateUserProfileRequest
    {
        public string Username { get; set; }
        public string Email { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Department { get; set; }
    }

    public class ChangePasswordRequest
    {
        public string OldPassword { get; set; }
        public string NewPassword { get; set; }
        public string ConfirmPassword { get; set; }
    }

    public class UserFilter
    {
        public int PageNumber { get; set; } = 1;
        public int PageSize { get; set; } = 10;
        public string Role { get; set; }
        public string Department { get; set; }
        public bool? IsActive { get; set; }
    }
}