using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Tiku.Application.Auth;
using Tiku.Domain.Tenancy;

namespace Tiku.Api.Contracts;

/// <summary>
/// PasswordLogin请求 DTO。
/// </summary>
public sealed class PasswordLoginDto
{
    /// <summary>
    /// 认证域。
    /// </summary>
    [Required]
    public AuthRealm? Realm { get; set; }
    /// <summary>
    /// 租户编码。
    /// </summary>
    [StringLength(100)]
    [Description("平台控制域名登录时使用的租户代码；自定义域名登录可省略。")]
    public string? TenantCode { get; set; }

    /// <summary>
    /// 账号标识。
    /// </summary>
    [StringLength(320)]
    [Description("账号标识。tenant 可使用手机号，platform 可使用邮箱或用户名。")]
    public string? Identifier { get; set; }

    /// <summary>
    /// 兼容手机号字段；新客户端应使用 identifier。
    /// </summary>
    [StringLength(32)]
    [Description("兼容手机号字段；新客户端应使用 identifier。")]
    public string? Phone { get; set; }

    /// <summary>
    /// 密码。
    /// </summary>
    [Required]
    [StringLength(128, MinimumLength = 8)]
    [Description("用户密码。")]
    public string Password { get; set; } = string.Empty;
}

/// <summary>
/// SmsLogin请求 DTO。
/// </summary>
public sealed class SmsLoginDto
{
    /// <summary>
    /// 认证域。
    /// </summary>
    [Required]
    public AuthRealm? Realm { get; set; }
    /// <summary>
    /// 租户编码。
    /// </summary>
    [StringLength(100)]
    [Description("平台控制域名登录时使用的租户代码；自定义域名登录可省略。")]
    public string? TenantCode { get; set; }

    /// <summary>
    /// 手机号。
    /// </summary>
    [Required]
    [StringLength(32)]
    [Description("中国大陆手机号。")]
    public string Phone { get; set; } = string.Empty;

    /// <summary>
    /// 编码。
    /// </summary>
    [Required]
    [StringLength(12, MinimumLength = 4)]
    [Description("收到的短信验证码。")]
    public string Code { get; set; } = string.Empty;
}

/// <summary>
/// 发送短信验证码请求。
/// </summary>
public sealed class SendSmsCodeDto
{
    /// <summary>
    /// 认证域。
    /// </summary>
    [Required]
    public AuthRealm? Realm { get; set; }

    /// <summary>
    /// 租户编码。
    /// </summary>
    [StringLength(100)]
    public string? TenantCode { get; set; }

    /// <summary>
    /// 手机号。
    /// </summary>
    [Required]
    [StringLength(32)]
    public string Phone { get; set; } = string.Empty;

    /// <summary>
    /// 设备 ID。
    /// </summary>
    [StringLength(256)]
    public string? DeviceId { get; set; }
}

/// <summary>
/// O认证编码请求 DTO。
/// </summary>
public sealed class OAuthCodeDto
{
    /// <summary>
    /// 认证域。
    /// </summary>
    [Required]
    public AuthRealm? Realm { get; set; }
    /// <summary>
    /// 租户编码。
    /// </summary>
    [StringLength(100)]
    [Description("平台控制域名登录时使用的租户代码；自定义域名登录可省略。")]
    public string? TenantCode { get; set; }

    /// <summary>
    /// 编码。
    /// </summary>
    [Required]
    [StringLength(512)]
    [Description("OAuth 平台返回的一次性授权 code。")]
    public string Code { get; set; } = string.Empty;

    /// <summary>
    /// 公开用户资料。
    /// </summary>
    [Description("客户端可提供的公开用户资料，不允许包含 token/secret。当前后端先保留模板字段，后续按业务需要逐步使用。")]
    public Dictionary<string, object?>? Profile { get; set; }

    /// <summary>
    /// 语言。
    /// </summary>
    [StringLength(20)]
    [Description("微信用户资料语言，例如 zh_CN。当前微信小程序登录不会使用该字段。")]
    public string? Lang { get; set; }
}

/// <summary>
/// 刷新会话请求 DTO。
/// </summary>
public sealed class RefreshSessionDto
{
    /// <summary>
    /// 刷新令牌。
    /// </summary>
    [Required]
    [StringLength(2048)]
    [Description("refresh token。服务端只存储哈希，明文只返回给客户端一次。")]
    public string RefreshToken { get; set; } = string.Empty;
}

/// <summary>
/// Authenticated用户请求 DTO。
/// </summary>
public sealed class AuthenticatedUserDto
{
    /// <summary>
    /// 用户 ID。
    /// </summary>
    public Guid UserId { get; init; }

    /// <summary>
    /// 手机号。
    /// </summary>
    public string? Phone { get; init; }

    /// <summary>
    /// 邮箱。
    /// </summary>
    public string? Email { get; init; }

    /// <summary>
    /// 名称。
    /// </summary>
    public string? Name { get; init; }

    /// <summary>
    /// 认证域。
    /// </summary>
    public AuthRealm Realm { get; init; }

    /// <summary>
    /// 租户成员摘要。
    /// </summary>
    public TenantMembershipSummary? Tenant { get; init; }

    /// <summary>
    /// 访问令牌和刷新令牌。
    /// </summary>
    public AuthTokenPair Tokens { get; init; } = default!;

    public static AuthenticatedUserDto FromApplication(AuthenticatedUser user)
    {
        return new AuthenticatedUserDto
        {
            UserId = user.UserId,
            Phone = user.Phone,
            Email = user.Email,
            Name = user.Name,
            Realm = user.Realm,
            Tenant = user.Tenant,
            Tokens = user.Tokens
        };
    }
}

/// <summary>
/// 登录认证结果。
/// </summary>
public sealed class AuthenticationResultDto
{
    /// <summary>
    /// 状态。
    /// </summary>
    public AuthenticationStatus Status { get; init; }
    /// <summary>
    /// 用户信息。
    /// </summary>
    public AuthenticatedUserDto? User { get; init; }
    /// <summary>
    /// 挑战令牌。
    /// </summary>
    public string? ChallengeToken { get; init; }
    /// <summary>
    /// 挑战令牌过期时间。
    /// </summary>
    public DateTimeOffset? ChallengeExpiresAt { get; init; }

    public static AuthenticationResultDto FromApplication(AuthenticationResult result) => new()
    {
        Status = result.Status,
        User = result.User is null ? null : AuthenticatedUserDto.FromApplication(result.User),
        ChallengeToken = result.ChallengeToken,
        ChallengeExpiresAt = result.ChallengeExpiresAt
    };
}

/// <summary>
/// 首次登录必改密码请求。
/// </summary>
public sealed class RequiredPasswordChangeDto
{
    /// <summary>
    /// 挑战令牌。
    /// </summary>
    [Required]
    [StringLength(2048)]
    public string ChallengeToken { get; set; } = string.Empty;

    /// <summary>
    /// 新密码。
    /// </summary>
    [Required]
    [StringLength(128, MinimumLength = 8)]
    public string NewPassword { get; set; } = string.Empty;
}
