using Health.Infrastructure.Services;

namespace Health.WebApi.Endpoints;

/// <summary>
/// 认证相关 API 端点
/// </summary>
public static class AuthEndpoints
{
    public static void MapAuthEndpoints(this WebApplication app)
    {
        // 发送短信验证码
        app.MapPost("/api/auth/send-sms", async (
            SendSmsRequest request,
            AppDbContext db,
            SmsService sms,
            CancellationToken ct) =>
        {
            // 生成验证码
            var code = sms.GenerateCode();
            var vc = new VerificationCode
            {
                Id = Guid.NewGuid(),
                Phone = request.Phone,
                Code = code,
                ExpiresAt = DateTime.UtcNow.AddMinutes(5),
            };
            db.VerificationCodes.Add(vc);
            await db.SaveChangesAsync(ct);

            // 开发阶段：直接返回验证码（生产环境需去掉 devCode）
            await sms.SendCodeAsync(request.Phone, code);

            return Results.Ok(new { code = 0, data = new { success = true, devCode = code }, message = (string?)null });
        });

        // 手机号+验证码登录
        app.MapPost("/api/auth/login", async (
            LoginRequest request,
            AppDbContext db,
            JwtProvider jwt,
            CancellationToken ct) =>
        {
            // 开发阶段：任意6位数字通过
            var validCode = await db.VerificationCodes
                .Where(v => v.Phone == request.Phone
                    && v.Code == request.SmsCode
                    && v.ExpiresAt > DateTime.UtcNow
                    && !v.IsUsed)
                .OrderByDescending(v => v.CreatedAt)
                .FirstOrDefaultAsync(ct);

            if (validCode == null)
                return Results.Ok(new { code = 40001, data = (object?)null, message = "验证码错误或已过期" });

            validCode.IsUsed = true;

            // 查找或创建用户
            var user = await db.Users.FirstOrDefaultAsync(u => u.Phone == request.Phone, ct);
            var isNew = false;
            if (user == null)
            {
                user = new User
                {
                    Id = Guid.NewGuid(),
                    Phone = request.Phone,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow,
                };
                db.Users.Add(user);
                isNew = true;

                // 创建默认通知偏好
                db.NotificationPreferences.Add(new NotificationPreference
                {
                    Id = Guid.NewGuid(),
                    UserId = user.Id,
                });

                // 创建空健康档案
                db.HealthArchives.Add(new HealthArchive
                {
                    Id = Guid.NewGuid(),
                    UserId = user.Id,
                });
            }

            user.UpdatedAt = DateTime.UtcNow;
            await db.SaveChangesAsync(ct);

            // 生成 token
            var accessToken = jwt.GenerateAccessToken(user.Id, user.Phone);
            var refreshToken = jwt.GenerateRefreshToken();

            // 保存 refresh token
            db.RefreshTokens.Add(new RefreshToken
            {
                Id = Guid.NewGuid(),
                UserId = user.Id,
                Token = refreshToken,
                ExpiresAt = DateTime.UtcNow.AddDays(30),
            });
            await db.SaveChangesAsync(ct);

            return Results.Ok(new
            {
                code = 0,
                data = new
                {
                    accessToken,
                    refreshToken,
                    user = new
                    {
                        user.Id,
                        user.Phone,
                        user.Name,
                        user.Gender,
                        BirthDate = user.BirthDate?.ToString("yyyy-MM-dd"),
                        user.AvatarUrl,
                        isNew
                    }
                },
                message = (string?)null
            });
        });

        // 刷新 token
        app.MapPost("/api/auth/refresh", async (
            RefreshRequest request,
            AppDbContext db,
            JwtProvider jwt,
            CancellationToken ct) =>
        {
            var oldToken = await db.RefreshTokens
                .FirstOrDefaultAsync(t => t.Token == request.RefreshToken && !t.IsRevoked, ct);

            if (oldToken == null || oldToken.ExpiresAt < DateTime.UtcNow)
                return Results.Ok(new { code = 40002, data = (object?)null, message = "登录已过期，请重新登录" });

            // 吊销旧 token
            oldToken.IsRevoked = true;

            var user = await db.Users.FindAsync([oldToken.UserId], ct);
            if (user == null)
                return Results.Ok(new { code = 40002, data = (object?)null, message = "用户不存在" });

            // 生成新 token（续期）
            var accessToken = jwt.GenerateAccessToken(user.Id, user.Phone);
            var newRefreshToken = jwt.GenerateRefreshToken();
            db.RefreshTokens.Add(new RefreshToken
            {
                Id = Guid.NewGuid(),
                UserId = user.Id,
                Token = newRefreshToken,
                ExpiresAt = DateTime.UtcNow.AddDays(30),
            });
            await db.SaveChangesAsync(ct);

            return Results.Ok(new
            {
                code = 0,
                data = new { accessToken, refreshToken = newRefreshToken },
                message = (string?)null
            });
        });

        // 登出
        app.MapPost("/api/auth/logout", async (
            RefreshRequest request,
            AppDbContext db,
            CancellationToken ct) =>
        {
            var token = await db.RefreshTokens
                .FirstOrDefaultAsync(t => t.Token == request.RefreshToken, ct);
            if (token != null) token.IsRevoked = true;
            await db.SaveChangesAsync(ct);

            return Results.Ok(new { code = 0, data = new { success = true }, message = (string?)null });
        });
    }
}

// ---- 请求 DTO ----
public sealed record SendSmsRequest(string Phone);
public sealed record LoginRequest(string Phone, string SmsCode);
public sealed record RefreshRequest(string RefreshToken);
