using System.Security.Cryptography;
using Application.Auth;
using Application.Students.DTOs;
using Domain.Ports.Repositories;
using MediatR;
using Microsoft.Extensions.Configuration;

namespace Application.Students.Commands;

public record RegenerateActivationCodeCommand(int StudentId, string? BaseUrl = null)
    : IRequest<CreateStudentResult?>;

public class RegenerateActivationCodeHandler(
    IStudentRepository studentRepository,
    IPasswordService passwordService,
    IUnitOfWork unitOfWork,
    IConfiguration configuration
) : IRequestHandler<RegenerateActivationCodeCommand, CreateStudentResult?>
{
    private static readonly TimeSpan ActivationExpiration = TimeSpan.FromHours(48);

    public async Task<CreateStudentResult?> Handle(RegenerateActivationCodeCommand request, CancellationToken ct)
    {
        var student = await studentRepository.GetByIdAsync(request.StudentId, ct);

        if (student == null)
            return null;

        // Only regenerate if student is not yet activated
        if (student.IsActivated)
            return null;

        // Generate new activation code
        var activationCode = GenerateActivationCode();
        var codeHash = passwordService.HashPassword(activationCode);
        student.SetActivationCode(codeHash, ActivationExpiration);

        studentRepository.Update(student);
        await unitOfWork.SaveChangesAsync(ct);

        var baseUrl = request.BaseUrl ?? configuration["App:BaseUrl"] ?? "http://localhost:4200";
        var activationUrl = $"{baseUrl}/activate?code={activationCode}";

        var studentDto = new StudentDto(student.Id, student.Name, student.Email.Value, 0, []);

        return new CreateStudentResult(
            studentDto,
            activationCode,
            activationUrl,
            student.ActivationExpiresAt!.Value);
    }

    private static string GenerateActivationCode()
    {
        const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
        var bytes = RandomNumberGenerator.GetBytes(12);
        return new string(bytes.Select(b => chars[b % chars.Length]).ToArray());
    }
}
