using Health.Application.Admin;

namespace Health.Infrastructure.Admin;

public sealed class AdminService(AppDbContext db) : IAdminService
{
    private readonly AppDbContext _db = db;

    public async Task<AdminResult> ListDoctorsAsync(CancellationToken ct)
    {
        var doctors = await _db.Doctors.AsNoTracking().OrderBy(x => x.CreatedAt)
            .Select(x => new { x.Id, x.Name, x.Title, x.Department, x.Phone, x.ProfessionalDirection, x.IsActive, x.AvatarUrl, x.Introduction, x.CreatedAt })
            .ToListAsync(ct);
        return Ok(doctors);
    }

    public async Task<AdminResult> AddDoctorAsync(AddDoctorCommand command, CancellationToken ct)
    {
        var phone = command.Phone.Trim();
        var name = command.Name.Trim();
        if (string.IsNullOrWhiteSpace(phone)) return Error(40001, "手机号不能为空");
        if (string.IsNullOrWhiteSpace(name)) return Error(40002, "姓名不能为空");
        if (await _db.Users.AnyAsync(x => x.Phone == phone, ct) ||
            await _db.Doctors.AnyAsync(x => x.Phone == phone, ct))
            return Error(40003, "该手机号已被其他账号使用");

        var doctor = new Doctor
        {
            Id = Guid.NewGuid(), Name = name, Title = command.Title?.Trim(), Department = command.Department?.Trim(),
            Phone = phone, ProfessionalDirection = command.ProfessionalDirection?.Trim(), IsActive = true, CreatedAt = DateTime.UtcNow,
        };
        var user = new User
        {
            Id = Guid.NewGuid(), Phone = phone, Role = "Doctor", Name = name,
            CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow
        };
        _db.Doctors.Add(doctor);
        _db.Users.Add(user);
        _db.DoctorProfiles.Add(new DoctorProfile
        {
            Id = Guid.NewGuid(), UserId = user.Id, DoctorId = doctor.Id, Name = name,
            Title = doctor.Title, Department = doctor.Department, IsActive = true,
            CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow,
        });
        await _db.SaveChangesAsync(ct);
        return Ok(new { doctor.Id, doctor.Name });
    }

    public async Task<AdminResult> UpdateDoctorAsync(Guid id, UpdateDoctorCommand command, CancellationToken ct)
    {
        var doctor = await _db.Doctors.FindAsync([id], ct);
        if (doctor == null) return Error(404, "医生不存在");
        var profile = await _db.DoctorProfiles.Include(x => x.User)
            .FirstOrDefaultAsync(x => x.DoctorId == id, ct);
        if (profile == null) return Error(40901, "医生登录资料不完整，请联系技术人员修复");

        var user = profile.User;
        if (command.Phone != null)
        {
            var phone = command.Phone.Trim();
            if (phone.Length == 0) return Error(40001, "手机号不能为空");
            if (await _db.Users.AnyAsync(x => x.Id != user.Id && x.Phone == phone, ct) ||
                await _db.Doctors.AnyAsync(x => x.Id != id && x.Phone == phone, ct))
                return Error(40003, "该手机号已被其他账号使用");
            doctor.Phone = phone;
            user.Phone = phone;
        }
        if (command.Name != null)
        {
            var name = command.Name.Trim();
            if (name.Length == 0) return Error(40002, "姓名不能为空");
            doctor.Name = name;
            user.Name = name;
            profile.Name = name;
        }
        if (command.Title != null)
        {
            doctor.Title = command.Title.Trim();
            profile.Title = doctor.Title;
        }
        if (command.Department != null)
        {
            doctor.Department = command.Department.Trim();
            profile.Department = doctor.Department;
        }
        if (command.ProfessionalDirection != null)
            doctor.ProfessionalDirection = command.ProfessionalDirection.Trim();
        user.UpdatedAt = DateTime.UtcNow;
        profile.UpdatedAt = DateTime.UtcNow;
        await _db.SaveChangesAsync(ct);
        return Ok(new { doctor.Id });
    }

    public async Task<AdminResult> ToggleDoctorAsync(Guid id, CancellationToken ct)
    {
        var doctor = await _db.Doctors.FindAsync([id], ct);
        if (doctor == null) return Error(404, "医生不存在");
        var profile = await _db.DoctorProfiles.FirstOrDefaultAsync(x => x.DoctorId == id, ct);
        if (profile == null) return Error(40901, "医生登录资料不完整，请联系技术人员修复");
        doctor.IsActive = !doctor.IsActive;
        profile.IsActive = doctor.IsActive;
        profile.UpdatedAt = DateTime.UtcNow;
        await _db.SaveChangesAsync(ct);
        return Ok(new { doctor.Id, doctor.IsActive });
    }

    public async Task<AdminResult> DeleteDoctorAsync(Guid id, CancellationToken ct)
    {
        var doctor = await _db.Doctors.FindAsync([id], ct);
        if (doctor == null) return Error(404, "医生不存在");

        if (await _db.Users.AnyAsync(x => x.Role == "User" && x.DoctorId == id, ct))
            return Error(40004, "该医生仍有绑定患者，请先停用，不能直接删除");
        if (await _db.Consultations.AnyAsync(x => x.DoctorId == id, ct))
            return Error(40005, "该医生已有问诊记录，只能停用，不能删除");

        var profile = await _db.DoctorProfiles.Include(x => x.User)
            .FirstOrDefaultAsync(x => x.DoctorId == id, ct);
        if (profile != null)
        {
            var user = profile.User;
            var refreshTokens = await _db.RefreshTokens.Where(x => x.UserId == user.Id).ToListAsync(ct);
            _db.RefreshTokens.RemoveRange(refreshTokens);
            _db.DoctorProfiles.Remove(profile);
            _db.Users.Remove(user);
        }
        _db.Doctors.Remove(doctor);
        await _db.SaveChangesAsync(ct);
        return Ok(new { success = true });
    }

    public async Task<AdminResult> ListPatientsAsync(string? search, int page, int pageSize, CancellationToken ct)
    {
        page = Math.Max(page, 1);
        pageSize = Math.Clamp(pageSize, 1, 100);
        var query = _db.Users.AsNoTracking().Where(x => x.Role == "User");
        if (!string.IsNullOrWhiteSpace(search))
            query = query.Where(x =>
                (x.Name != null && x.Name.Contains(search)) ||
                (x.Phone != null && x.Phone.Contains(search)));
        var total = await query.CountAsync(ct);
        var patients = await query.OrderByDescending(x => x.CreatedAt).Skip((page - 1) * pageSize).Take(pageSize)
            .Select(x => new { x.Id, x.Name, x.Phone, x.Gender, x.BirthDate, x.CreatedAt, DoctorName = x.Doctor != null ? x.Doctor.Name : null, DoctorDepartment = x.Doctor != null ? x.Doctor.Department : null })
            .ToListAsync(ct);
        return Ok(new { patients, total, page, pageSize });
    }

    private static AdminResult Ok(object data) => new(0, data);
    private static AdminResult Error(int code, string message) => new(code, null, message);
}
