using Microsoft.EntityFrameworkCore;
using System.Security.Cryptography;
using System.Text.Json;
using bitforum.Constants;
using bitforum.Models.Account;

namespace bitforum.Repository
{
    public interface IEmailVerifyTokenRepository
    {
        /// <summary>
        /// 새 토큰 생성 및 저장
        /// </summary>
        public Task<string> GenerateTokenAsync(string email, VerificationType type, AdditionalData? additional = null);

        /// <summary>
        /// 토큰 검증 및 사용 처리
        /// </summary>
        public Task<EmailVerifyToken?> ValidateTokenAsync(string token, VerificationType type);

        /// <summary>
        /// 만료된 토큰 삭제
        /// </summary>
        public Task CleanupExpiredTokensAsync();
    }

    public class EmailVerifyTokenRepository : IEmailVerifyTokenRepository
    {
        private readonly DefaultDbContext _db;
        private readonly int _tokenExpirationMinutes = 60;

        public EmailVerifyTokenRepository(DefaultDbContext db)
        {
            _db = db;
        }

        public async Task<string> GenerateTokenAsync(string email, VerificationType type, AdditionalData? additional = null)
        {
            _db.EmailVerifyToken.RemoveRange(
                _db.EmailVerifyToken.Where(x => x.Email == email && x.Type == type)
            );

            var token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
            var expiration = DateTime.UtcNow.AddMinutes(_tokenExpirationMinutes);

            _db.EmailVerifyToken.Add(new EmailVerifyToken
            {
                Email = email,
                Token = token,
                Expiration = expiration,
                Type = type,
                Additional = additional == null ? null : JsonSerializer.Serialize(additional)
            });

            await _db.SaveChangesAsync();

            return token;
        }

        public async Task<EmailVerifyToken?> ValidateTokenAsync(string token, VerificationType type)
        {
            var data = await _db.EmailVerifyToken.FirstOrDefaultAsync(x => x.Token == token && x.Type == type && !x.IsVerified && x.Expiration > DateTime.UtcNow);

            if (data == null)
            {
                return null;
            }

            data.IsVerified = true;
            await _db.SaveChangesAsync();

            return data;
        }

        public async Task CleanupExpiredTokensAsync()
        {
            _db.EmailVerifyToken.RemoveRange(
                _db.EmailVerifyToken.Where(x => x.Expiration < DateTime.UtcNow)
            );

            await _db.SaveChangesAsync();
        }
    }
}
