using System;
using System.Globalization;
using Microsoft.AspNetCore.Http;

namespace FrontOffice.Main.Utilities;

public interface IDeviceDetector
{
    DeviceInfo Detect(string? userAgent = null);
    bool IsMobile(string? userAgent = null);
    bool IsTablet(string? userAgent = null);
    bool IsDesktop(string? userAgent = null);
}

public sealed class DeviceDetector : IDeviceDetector
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public DeviceDetector(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
    }

    public DeviceInfo Detect(string? userAgent = null)
    {
        string? headerUa = null;
        var http = _httpContextAccessor.HttpContext;
        if (http != null)
        {
            headerUa = http.Request.Headers["User-Agent"].ToString();
        }

        var ua = userAgent ?? headerUa ?? string.Empty;
        var uaLower = ua.ToLower(CultureInfo.InvariantCulture);

        // Bots
        if (ContainsAny(uaLower, "bot", "spider", "crawler", "bingpreview", "facebookexternalhit"))
        {
            return new DeviceInfo(DeviceType.Bot, DetectOs(uaLower), DetectBrowser(uaLower), ua);
        }

        var type = DetectDeviceType(uaLower);
        var os = DetectOs(uaLower);
        var browser = DetectBrowser(uaLower);

        return new DeviceInfo(type, os, browser, ua);
    }

    public bool IsMobile(string? userAgent = null) => Detect(userAgent).Type == DeviceType.Mobile;
    public bool IsTablet(string? userAgent = null) => Detect(userAgent).Type == DeviceType.Tablet;
    public bool IsDesktop(string? userAgent = null) => Detect(userAgent).Type == DeviceType.Desktop;

    private static DeviceType DetectDeviceType(string uaLower)
    {
        if (string.IsNullOrWhiteSpace(uaLower)) return DeviceType.Unknown;

        // Tablets
        if (ContainsAny(uaLower, "ipad", "tablet", "kindle", "silk", "playbook"))
            return DeviceType.Tablet;

        // Mobiles (exclude tablets when possible)
        if (ContainsAny(uaLower, "mobi", "iphone", "ipod", "android") && !uaLower.Contains("tablet"))
            return DeviceType.Mobile;

        // Smart TV
        if (ContainsAny(uaLower, "smart-tv", "smarttv", "hbbtv", "appletv"))
            return DeviceType.Desktop; // treat TVs as desktop-like

        return DeviceType.Desktop;
    }

    private static string DetectOs(string uaLower)
    {
        if (string.IsNullOrWhiteSpace(uaLower)) return "Unknown";
        if (uaLower.Contains("windows nt")) return "Windows";
        if (uaLower.Contains("android")) return "Android";
        if (uaLower.Contains("iphone") || uaLower.Contains("ipad") || uaLower.Contains("ipod") || uaLower.Contains("ios")) return "iOS";
        if (uaLower.Contains("mac os x") || uaLower.Contains("macintosh")) return "macOS";
        if (uaLower.Contains("linux")) return "Linux";
        if (uaLower.Contains("cros")) return "ChromeOS";
        return "Unknown";
    }

    private static string DetectBrowser(string uaLower)
    {
        if (string.IsNullOrWhiteSpace(uaLower)) return "Unknown";
        if (uaLower.Contains("edg/")) return "Edge"; // Chromium Edge
        if (uaLower.Contains("edge/")) return "Edge"; // Legacy Edge
        if (uaLower.Contains("opr/") || uaLower.Contains("opera")) return "Opera";
        if (uaLower.Contains("chrome/") && !uaLower.Contains("edg/") && !uaLower.Contains("opr/") && !uaLower.Contains("chromium")) return "Chrome";
        if (uaLower.Contains("safari") && !uaLower.Contains("chrome")) return "Safari";
        if (uaLower.Contains("firefox")) return "Firefox";
        if (uaLower.Contains("msie") || uaLower.Contains("trident/")) return "IE";
        if (uaLower.Contains("chromium")) return "Chromium";
        return "Unknown";
    }

    private static bool ContainsAny(string source, params string[] values)
    {
        foreach (var v in values)
        {
            if (source.Contains(v)) return true;
        }
        return false;
    }
}

public enum DeviceType
{
    Unknown = 0,
    Mobile = 1,
    Tablet = 2,
    Desktop = 3,
    Bot = 4
}

public sealed record DeviceInfo(DeviceType Type, string Os, string Browser, string UserAgent);
