using JobsMedical.Web.Services.Scraping;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Hosting;

namespace JobsMedical.Web.Services;

/// <summary>
/// One-time-code issuing/verification. Codes live in memory for 5 minutes. When SMS is configured
/// (admin settings) the code is sent via the gateway and NOT returned; otherwise it's returned so
/// the dev login page can display it.
/// </summary>
public class OtpService
{
    private readonly IMemoryCache _cache;
    private readonly ISmsSender _sms;
    private readonly SettingsService _settings;
    private readonly IHostEnvironment _env;

    public OtpService(IMemoryCache cache, ISmsSender sms, SettingsService settings, IHostEnvironment env)
    {
        _cache = cache;
        _sms = sms;
        _settings = settings;
        _env = env;
    }

    private static string Key(string phone) => $"otp:{Normalize(phone)}";

    /// <summary>
    /// Generate + store a 5-digit code. If SMS is enabled, send it and return null (don't reveal);
    /// otherwise return the code so the dev login screen can show it.
    /// </summary>
    public async Task<string?> IssueAsync(string phone)
    {
        var code = Random.Shared.Next(10000, 100000).ToString();
        _cache.Set(Key(phone), code, TimeSpan.FromMinutes(5));

        var settings = await _settings.GetAsync();
        // In Development (local Docker / dotnet run) never call the SMS gateway — always show the
        // code on the login screen. In Production, send via SMS only when it's enabled.
        if (settings.SmsEnabled && !_env.IsDevelopment())
        {
            await _sms.SendOtpAsync(phone, code, settings);
            return null;   // sent via SMS — don't reveal it
        }
        return code;       // local/dev (or SMS off): surface it on screen
    }

    public bool Verify(string phone, string code)
    {
        if (_cache.TryGetValue(Key(phone), out string? stored) && stored == code?.Trim())
        {
            _cache.Remove(Key(phone));
            return true;
        }
        return false;
    }

    /// <summary>Normalize Iranian mobile numbers (Persian digits → Latin, strip spaces).</summary>
    public static string Normalize(string phone)
    {
        var chars = phone.Trim().ToCharArray();
        for (var i = 0; i < chars.Length; i++)
            if (chars[i] >= '۰' && chars[i] <= '۹') chars[i] = (char)('0' + (chars[i] - '۰'));
        return new string(chars).Replace(" ", "").Replace("-", "");
    }
}
