using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using IamService.API.Application.Common;
using IamService.API.Application.Commands.UserProfiles;
using IamService.API.Application.Queries.UserProfiles;

namespace IamService.API.Controllers;

/// <summary>
/// EN: User profiles controller.
/// VI: Controller profile user.
/// </summary>
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/users")]
[Authorize(AuthenticationSchemes = "Bearer")]
[SwaggerTag("User profile management endpoints")]
public class UserProfilesController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<UserProfilesController> _logger;

    public UserProfilesController(
        IMediator mediator,
        ILogger<UserProfilesController> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }

    /// <summary>
    /// EN: Get user profile.
    /// VI: Lấy profile user.
    /// </summary>
    [HttpGet("{userId:guid}/profile")]
    [SwaggerOperation(Summary = "Get user profile", OperationId = "GetUserProfile")]
    [SwaggerResponse(StatusCodes.Status200OK, "Profile found", typeof(ApiResponse<UserProfileResponse>))]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Profile not found")]
    public async Task<IActionResult> GetUserProfile(
        [FromRoute] Guid userId,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetUserProfileQuery(userId), cancellationToken);

        if (result == null)
            return NotFound(ApiResponse<UserProfileResponse>.Fail("PROFILE_NOT_FOUND", $"Profile for user {userId} not found."));

        return Ok(ApiResponse<UserProfileResponse>.Ok(MapToResponse(result)));
    }

    /// <summary>
    /// EN: Update user profile.
    /// VI: Cập nhật profile user.
    /// </summary>
    [HttpPut("{userId:guid}/profile")]
    [SwaggerOperation(Summary = "Update user profile", OperationId = "UpdateUserProfile")]
    [SwaggerResponse(StatusCodes.Status200OK, "Profile updated", typeof(ApiResponse<UserProfileResponse>))]
    public async Task<IActionResult> UpdateUserProfile(
        [FromRoute] Guid userId,
        [FromBody] UpdateProfileRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new UpdateUserProfileCommand(
            userId,
            request.Bio,
            request.Timezone,
            request.Locale,
            request.AvatarUrl);

        var result = await _mediator.Send(command, cancellationToken);

        return Ok(ApiResponse<UserProfileResponse>.Ok(new UserProfileResponse
        {
            Id = result.ProfileId,
            UserId = result.UserId,
            Bio = result.Bio,
            Timezone = result.Timezone,
            Locale = result.Locale,
            AvatarUrl = result.AvatarUrl,
            UpdatedAt = result.UpdatedAt
        }));
    }

    /// <summary>
    /// EN: Set profile attribute.
    /// VI: Đặt attribute profile.
    /// </summary>
    [HttpPut("{userId:guid}/profile/attributes/{key}")]
    [SwaggerOperation(Summary = "Set profile attribute", OperationId = "SetProfileAttribute")]
    [SwaggerResponse(StatusCodes.Status200OK, "Attribute set", typeof(ApiResponse<ProfileAttributeResponse>))]
    public async Task<IActionResult> SetProfileAttribute(
        [FromRoute] Guid userId,
        [FromRoute] string key,
        [FromBody] SetAttributeRequest request,
        CancellationToken cancellationToken = default)
    {
        var command = new SetProfileAttributeCommand(userId, key, request.Value, request.ValueType);
        var result = await _mediator.Send(command, cancellationToken);

        return Ok(ApiResponse<ProfileAttributeResponse>.Ok(new ProfileAttributeResponse
        {
            Key = result.Key,
            Value = result.Value,
            ValueType = result.ValueType
        }));
    }

    private static UserProfileResponse MapToResponse(UserProfileDto dto) => new()
    {
        Id = dto.Id,
        UserId = dto.UserId,
        Bio = dto.Bio,
        AvatarUrl = dto.AvatarUrl,
        Timezone = dto.Timezone,
        Locale = dto.Locale,
        DateOfBirth = dto.DateOfBirth,
        PhoneNumber = dto.PhoneNumber != null
            ? new PhoneNumberResponseDto { CountryCode = dto.PhoneNumber.CountryCode, NationalNumber = dto.PhoneNumber.NationalNumber }
            : null,
        Address = dto.Address != null
            ? new AddressResponseDto 
            { 
                Street = dto.Address.Street, 
                City = dto.Address.City, 
                State = dto.Address.State, 
                PostalCode = dto.Address.PostalCode, 
                Country = dto.Address.Country 
            }
            : null,
        Attributes = dto.Attributes.Select(a => new ProfileAttributeResponse { Key = a.Key, Value = a.Value, ValueType = a.ValueType }).ToList(),
        CreatedAt = dto.CreatedAt,
        UpdatedAt = dto.UpdatedAt
    };
}

#region Request/Response Models

public class UpdateProfileRequest
{
    public string? Bio { get; set; }
    public string? Timezone { get; set; }
    public string? Locale { get; set; }
    public string? AvatarUrl { get; set; }
}

public class SetAttributeRequest
{
    public string Value { get; set; } = string.Empty;
    /// <example>String</example>
    public string ValueType { get; set; } = "String";  // String, Number, Boolean, Date, Json
}

public class UserProfileResponse
{
    public Guid Id { get; set; }
    public Guid UserId { get; set; }
    public string? Bio { get; set; }
    public string? AvatarUrl { get; set; }
    public string? Timezone { get; set; }
    public string? Locale { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public PhoneNumberResponseDto? PhoneNumber { get; set; }
    public AddressResponseDto? Address { get; set; }
    public List<ProfileAttributeResponse> Attributes { get; set; } = [];
    public DateTime CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
}

public class PhoneNumberResponseDto
{
    public string CountryCode { get; set; } = string.Empty;
    public string NationalNumber { get; set; } = string.Empty;
}

public class AddressResponseDto
{
    public string? Street { get; set; }
    public string? City { get; set; }
    public string? State { get; set; }
    public string? PostalCode { get; set; }
    public string? Country { get; set; }
}

public class ProfileAttributeResponse
{
    public string Key { get; set; } = string.Empty;
    public string Value { get; set; } = string.Empty;
    public string ValueType { get; set; } = string.Empty;
}

#endregion
