using System.IO;
using System.Text.Json;
using System.Text.RegularExpressions;
using NexusShell.Models.Browser;

namespace NexusShell.Services;

public sealed class NexusBrowserNavigationService
{
    private static readonly string[] BlockedPrefixes =
    [
        "file://",
        "cmd:",
        "powershell:",
        "ms-settings:",
        "shell:",
        "javascript:",
    ];

    private readonly string _historyPath;
    private readonly List<BrowserHistoryEntry> _history = [];

    public NexusBrowserNavigationService()
    {
        var folder = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            "NinjaNexus",
            "browser");
        Directory.CreateDirectory(folder);
        _historyPath = Path.Combine(folder, "history.json");
        LoadHistory();
    }

    public IReadOnlyList<BrowserHistoryEntry> History => _history;

    public bool IsBlocked(string input)
    {
        if (string.IsNullOrWhiteSpace(input))
        {
            return false;
        }

        var trimmed = input.Trim();
        foreach (var prefix in BlockedPrefixes)
        {
            if (trimmed.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
        }

        return false;
    }

    public NavigationResolveResult ResolveInput(string input)
    {
        if (string.IsNullOrWhiteSpace(input))
        {
            return NavigationResolveResult.Home();
        }

        var trimmed = input.Trim();
        if (IsBlocked(trimmed))
        {
            return NavigationResolveResult.Blocked(NexusBrowserConstants.BlockedMessage);
        }

        if (string.Equals(trimmed, NexusBrowserConstants.HomeUrl, StringComparison.OrdinalIgnoreCase) ||
            string.Equals(trimmed, "nexus:home", StringComparison.OrdinalIgnoreCase))
        {
            return NavigationResolveResult.Home();
        }

        if (LooksLikeUrl(trimmed))
        {
            var url = NormalizeUrl(trimmed);
            if (IsBlocked(url))
            {
                return NavigationResolveResult.Blocked(NexusBrowserConstants.BlockedMessage);
            }

            return NavigationResolveResult.Navigate(url);
        }

        var searchUrl = $"https://www.google.com/search?q={Uri.EscapeDataString(trimmed)}";
        return NavigationResolveResult.Navigate(searchUrl);
    }

    public BrowserSecurityState GetSecurityState(string url, bool isLoading)
    {
        if (isLoading)
        {
            return BrowserSecurityState.Loading;
        }

        if (string.IsNullOrWhiteSpace(url) ||
            url.StartsWith("nexus:", StringComparison.OrdinalIgnoreCase) ||
            url.StartsWith("about:", StringComparison.OrdinalIgnoreCase) ||
            url.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
        {
            return BrowserSecurityState.Local;
        }

        if (url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            return BrowserSecurityState.Secure;
        }

        if (url.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
        {
            return BrowserSecurityState.NotSecure;
        }

        return BrowserSecurityState.Local;
    }

    public void RecordVisit(string url, string title)
    {
        if (string.IsNullOrWhiteSpace(url) ||
            url.StartsWith("nexus:", StringComparison.OrdinalIgnoreCase) ||
            url.StartsWith("about:", StringComparison.OrdinalIgnoreCase) ||
            url.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        var entry = new BrowserHistoryEntry
        {
            Url = url,
            Title = string.IsNullOrWhiteSpace(title) ? url : title,
            VisitedAt = DateTimeOffset.UtcNow,
        };

        _history.Insert(0, entry);
        if (_history.Count > 500)
        {
            _history.RemoveRange(500, _history.Count - 500);
        }

        SaveHistory();
    }

    private static bool LooksLikeUrl(string input)
    {
        if (input.Contains(' ') && !input.Contains('.'))
        {
            return false;
        }

        if (Regex.IsMatch(input, @"^[a-zA-Z][a-zA-Z0-9+\-.]*:", RegexOptions.None, TimeSpan.FromMilliseconds(100)))
        {
            return true;
        }

        return input.Contains('.') || input.StartsWith("localhost", StringComparison.OrdinalIgnoreCase);
    }

    private static string NormalizeUrl(string input)
    {
        if (input.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
            input.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            return input;
        }

        return $"https://{input}";
    }

    private void LoadHistory()
    {
        try
        {
            if (!File.Exists(_historyPath))
            {
                return;
            }

            var json = File.ReadAllText(_historyPath);
            var entries = JsonSerializer.Deserialize<List<BrowserHistoryEntry>>(json);
            if (entries is not null)
            {
                _history.Clear();
                _history.AddRange(entries);
            }
        }
        catch
        {
            // POC: ignore corrupt history
        }
    }

    private void SaveHistory()
    {
        try
        {
            var json = JsonSerializer.Serialize(_history, new JsonSerializerOptions
            {
                WriteIndented = true,
            });
            File.WriteAllText(_historyPath, json);
        }
        catch
        {
            // POC: ignore persist failures
        }
    }
}

public sealed class NavigationResolveResult
{
    public bool IsBlocked { get; init; }
    public bool IsHome { get; init; }
    public string Url { get; init; } = NexusBrowserConstants.HomeUrl;
    public string? BlockMessage { get; init; }

    public static NavigationResolveResult Home() => new() { IsHome = true, Url = NexusBrowserConstants.HomeUrl };

    public static NavigationResolveResult Blocked(string message) =>
        new() { IsBlocked = true, BlockMessage = message };

    public static NavigationResolveResult Navigate(string url) => new() { Url = url };
}
