using System.Net;
using System.Text.RegularExpressions;
using JobsMedical.Web.Models;

namespace JobsMedical.Web.Services.Scraping;

/// <summary>
/// Reads public Telegram channels via the web preview (https://t.me/s/&lt;channel&gt;) — no bot
/// token needed for public channels. Enabled + channel list come from the admin settings (DB).
/// </summary>
public class TelegramListingSource : IListingSource
{
    private readonly ScrapeHttpClients _clients;
    private readonly ILogger<TelegramListingSource> _log;

    public TelegramListingSource(ScrapeHttpClients clients, ILogger<TelegramListingSource> log)
    {
        _clients = clients;
        _log = log;
    }

    public string Name => "تلگرام";

    public async Task<IReadOnlyList<ScrapedItem>> FetchAsync(AppSetting s, CancellationToken ct = default)
    {
        var channels = AppSetting.SplitList(s.TelegramChannels);
        if (!s.TelegramEnabled || channels.Count == 0) return Array.Empty<ScrapedItem>();

        var client = _clients.For(s, s.TelegramUseProxy);
        var items = new List<ScrapedItem>();
        foreach (var ch in channels.Select(c => c.TrimStart('@')).Where(c => c.Length > 0))
        {
            try
            {
                var html = await client.GetStringAsync($"https://t.me/s/{ch}", ct);
                foreach (var text in ExtractMessages(html).Take(20))
                    items.Add(new ScrapedItem($"تلگرام/{ch}", text, $"https://t.me/{ch}"));
            }
            catch (Exception ex) { _log.LogWarning(ex, "Telegram fetch failed for {Channel}", ch); }
        }
        return items;
    }

    private static IEnumerable<string> ExtractMessages(string html)
    {
        foreach (Match m in Regex.Matches(html,
            "<div class=\"tgme_widget_message_text[^\"]*\"[^>]*>(.*?)</div>", RegexOptions.Singleline))
        {
            var text = HtmlUtil.ToPlainText(m.Groups[1].Value);
            if (text.Length >= 15) yield return text;
        }
    }
}

internal static class HtmlUtil
{
    public static string ToPlainText(string html)
    {
        var s = Regex.Replace(html, "<br\\s*/?>", "\n", RegexOptions.IgnoreCase);
        s = Regex.Replace(s, "<[^>]+>", "");
        s = WebUtility.HtmlDecode(s);
        s = Regex.Replace(s, "[ \\t]+", " ");
        return s.Trim();
    }

    /// <summary>Convert Persian/Arabic-Indic digits to Latin.</summary>
    public static string ToLatinDigits(string s)
    {
        var a = s.ToCharArray();
        for (var i = 0; i < a.Length; i++)
        {
            if (a[i] >= '۰' && a[i] <= '۹') a[i] = (char)('0' + (a[i] - '۰'));
            else if (a[i] >= '٠' && a[i] <= '٩') a[i] = (char)('0' + (a[i] - '٠'));
        }
        return new string(a);
    }

    /// <summary>
    /// Pull Iranian phone numbers out of a page's HTML — including ones a site reveals on click
    /// (often still present as a tel: link, a data-*phone* attribute, or JSON-LD "telephone").
    /// Returns normalized numbers (mobiles as 09xxxxxxxxx, landlines with leading 0), mobiles first.
    /// </summary>
    public static List<string> HarvestPhones(string html)
    {
        if (string.IsNullOrEmpty(html)) return new();
        var latin = ToLatinDigits(html);
        var found = new List<string>();

        void Add(string raw)
        {
            var d = Regex.Replace(raw, @"\D", "");
            if (d.StartsWith("0098")) d = "0" + d[4..];
            else if (d.StartsWith("98") && d.Length >= 12) d = "0" + d[2..];
            if (Regex.IsMatch(d, @"^9\d{9}$")) d = "0" + d;          // 9xxxxxxxxx → 09xxxxxxxxx
            bool ok = Regex.IsMatch(d, @"^09\d{9}$")                  // mobile
                   || Regex.IsMatch(d, @"^0\d{10}$");                 // landline w/ area code
            if (ok && !found.Contains(d)) found.Add(d);
        }

        // Highest-signal sources first.
        foreach (Match m in Regex.Matches(latin, @"tel:\+?([\d\s\-]{7,})")) Add(m.Groups[1].Value);
        foreach (Match m in Regex.Matches(latin, "\"telephone\"\\s*:\\s*\"([^\"]+)\"")) Add(m.Groups[1].Value);
        foreach (Match m in Regex.Matches(latin, "data-[\\w-]*phone[\\w-]*=[\"']([^\"']+)[\"']", RegexOptions.IgnoreCase)) Add(m.Groups[1].Value);
        // Then bare numbers anywhere in the text — mobiles, then landlines. The (?<!\d)/(?!\d)
        // guards stop us from grabbing a slice of a longer numeric id / timestamp.
        foreach (Match m in Regex.Matches(latin, @"(?<!\d)(?:\+?98|0)?9\d{9}(?!\d)")) Add(m.Value);
        foreach (Match m in Regex.Matches(latin, @"(?<!\d)0\d{2,3}[\s-]?\d{7,8}(?!\d)")) Add(m.Value);

        return found.Take(3).ToList();
    }
}
