using System.Text.Json;
using System.Text.RegularExpressions;
using Backend.Contracts;
using Backend.Domain;
using System.Net;

namespace Backend.Common;

public static class SeasonMappings
{
    private static readonly Regex HtmlBreakRegex = new(@"<\s*br\s*/?>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static readonly Regex HtmlListItemOpenRegex = new(@"<\s*li\b[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static readonly Regex HtmlBlockCloseRegex = new(@"</\s*(p|div|li|ul|ol|h1|h2|h3|h4|h5|h6)\s*>", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    private static readonly Regex HtmlTagRegex = new(@"<[^>]*>", RegexOptions.Compiled);
    private static readonly Regex MultiNewlineRegex = new(@"\n{3,}", RegexOptions.Compiled);

    public static bool IsSeasonScheduleValid(
        DateOnly nominationStartsAt,
        DateOnly nominationEndsAt,
        DateOnly votingStartsAt,
        DateOnly votingEndsAt,
        DateOnly reviewStartsAt,
        DateOnly reviewEndsAt,
        DateOnly showDate)
    {
        return nominationStartsAt <= nominationEndsAt
            && nominationEndsAt <= votingStartsAt
            && votingStartsAt <= votingEndsAt
            && votingEndsAt <= reviewStartsAt
            && reviewStartsAt <= reviewEndsAt
            && reviewEndsAt <= showDate;
    }

    public static string BuildProfileUrl(string platform, string channelSlug)
    {
        var normalizedPlatform = platform.Trim().ToLowerInvariant();
        var platformKey = new string(normalizedPlatform.Where(char.IsLetterOrDigit).ToArray());
        var slug = channelSlug.Trim();
        var cleanSlug = slug.TrimStart('@');
        if (slug.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
            slug.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            return slug;
        }

        if (string.IsNullOrWhiteSpace(cleanSlug))
        {
            return "#";
        }

        if (string.IsNullOrWhiteSpace(platformKey))
        {
            return cleanSlug.Contains('.') ? $"https://{cleanSlug}" : "#";
        }

        return platformKey switch
        {
            "artstation" => $"https://www.artstation.com/{cleanSlug}",
            "bilibili" => $"https://space.bilibili.com/{cleanSlug}",
            "bluesky" => $"https://bsky.app/profile/{cleanSlug}",
            "booth" => $"https://{cleanSlug}.booth.pm",
            "cake" => $"https://cake.gg/@{cleanSlug}",
            "discord" => cleanSlug.Contains("discord.", StringComparison.OrdinalIgnoreCase) ? $"https://{cleanSlug}" : $"https://discord.gg/{cleanSlug}",
            "deviantart" => $"https://www.deviantart.com/{cleanSlug}",
            "facebook" => $"https://facebook.com/{cleanSlug}",
            "fanbox" => $"https://{cleanSlug}.fanbox.cc",
            "github" => $"https://github.com/{cleanSlug}",
            "instagram" => $"https://instagram.com/{cleanSlug}",
            "kick" => $"https://kick.com/{cleanSlug}",
            "kofi" or "ko-fi" => $"https://ko-fi.com/{cleanSlug}",
            "linktree" => $"https://linktr.ee/{cleanSlug}",
            "mastodon" => cleanSlug.Contains('@') ? $"https://{cleanSlug.Split('@').Last()}/@{cleanSlug.Split('@').First()}" : $"https://mastodon.social/@{cleanSlug}",
            "patreon" => $"https://patreon.com/{cleanSlug}",
            "picarto" or "picartotv" => $"https://picarto.tv/{cleanSlug}",
            "pinterest" => $"https://pinterest.com/{cleanSlug}",
            "pixiv" => $"https://www.pixiv.net/users/{cleanSlug}",
            "reddit" => $"https://reddit.com/user/{cleanSlug}",
            "skeb" => $"https://skeb.jp/@{cleanSlug}",
            "soundcloud" => $"https://soundcloud.com/{cleanSlug}",
            "spotify" => $"https://open.spotify.com/user/{cleanSlug}",
            "telegram" => $"https://t.me/{cleanSlug}",
            "threads" => $"https://threads.net/@{cleanSlug}",
            "tiktok" => $"https://tiktok.com/@{cleanSlug}",
            "trovo" => $"https://trovo.live/s/{cleanSlug}",
            "twitch" => $"https://twitch.tv/{cleanSlug}",
            "tumblr" => $"https://{cleanSlug}.tumblr.com",
            "vimeo" => $"https://vimeo.com/{cleanSlug}",
            "website" or "link" => cleanSlug.Contains('.') ? $"https://{cleanSlug}" : $"https://{cleanSlug}.com",
            "youtube" => cleanSlug.StartsWith("@", StringComparison.Ordinal) ? $"https://youtube.com/{cleanSlug}" : $"https://youtube.com/@{cleanSlug}",
            "x" or "twitter" => $"https://x.com/{cleanSlug}",
            _ => $"https://{platformKey}.com/{cleanSlug}",
        };
    }

    public static (string Platform, string Slug) InferProfileMetadataFromUrl(string? value, string fallbackName = "")
    {
        var trimmed = value?.Trim() ?? string.Empty;
        if (!Uri.TryCreate(trimmed, UriKind.Absolute, out var uri))
        {
            return ("Profil", fallbackName.Trim());
        }

        var host = uri.Host.Trim().ToLowerInvariant();
        var segments = uri.AbsolutePath
            .Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);

        var platform = host switch
        {
            var item when item.Contains("twitch.tv", StringComparison.Ordinal) => "Twitch",
            var item when item.Contains("youtube.com", StringComparison.Ordinal) || item.Contains("youtu.be", StringComparison.Ordinal) => "YouTube",
            var item when item.Contains("x.com", StringComparison.Ordinal) || item.Contains("twitter.com", StringComparison.Ordinal) => "X",
            var item when item.Contains("instagram.com", StringComparison.Ordinal) => "Instagram",
            var item when item.Contains("discord.gg", StringComparison.Ordinal) || item.Contains("discord.com", StringComparison.Ordinal) => "Discord",
            var item when item.Contains("kick.com", StringComparison.Ordinal) => "Kick",
            var item when item.Contains("cake.gg", StringComparison.Ordinal) => "Cake",
            _ => "Profil",
        };

        var slug = segments.LastOrDefault() ?? string.Empty;
        if (string.Equals(platform, "YouTube", StringComparison.Ordinal) && segments.Length > 0)
        {
            slug = segments.FirstOrDefault(segment => segment.StartsWith('@')) ?? slug;
        }

        slug = Uri.UnescapeDataString(slug).Trim().Trim('/');
        if (slug.StartsWith('@') && !string.Equals(platform, "YouTube", StringComparison.Ordinal))
        {
            slug = slug[1..];
        }

        if (string.IsNullOrWhiteSpace(slug))
        {
            slug = fallbackName.Trim();
        }

        return (platform, slug);
    }

    public static string NormalizeSeasonStreamUrl(string? value)
    {
        var trimmed = value?.Trim() ?? string.Empty;
        return string.IsNullOrWhiteSpace(trimmed) ? "https://twitch.tv/jayuhime" : trimmed;
    }

    public static string NormalizePlainTextContent(string? value)
    {
        var trimmed = value?.Trim() ?? string.Empty;
        if (string.IsNullOrWhiteSpace(trimmed))
        {
            return string.Empty;
        }

        var withBreakHints = HtmlBreakRegex.Replace(trimmed, "\n");
        withBreakHints = HtmlListItemOpenRegex.Replace(withBreakHints, "- ");
        withBreakHints = HtmlBlockCloseRegex.Replace(withBreakHints, "\n");
        withBreakHints = HtmlTagRegex.Replace(withBreakHints, " ");
        withBreakHints = WebUtility.HtmlDecode(withBreakHints).Replace("\r\n", "\n").Replace('\r', '\n');

        var normalizedLines = withBreakHints
            .Split('\n')
            .Select(line => line.Trim())
            .ToArray();

        return MultiNewlineRegex.Replace(string.Join('\n', normalizedLines), "\n\n").Trim();
    }

    public static string NormalizePhaseKey(string? currentPhase)
    {
        var value = currentPhase?.Trim().ToLowerInvariant() ?? string.Empty;
        if (value.Contains("abgeschlossen") || value.Contains("archiv") || value.Contains("complete") || value.Contains("ended"))
        {
            return "completed";
        }

        if (value.Contains("show"))
        {
            return "show";
        }

        if (value.Contains("aufbereit") || value.Contains("vorbereit") || value.Contains("pause") || value.Contains("review") || value.Contains("auswert"))
        {
            return "preparation";
        }

        if (value.Contains("vot"))
        {
            return "voting";
        }

        if (value.Contains("nomin"))
        {
            return "nomination";
        }

        return "nomination";
    }

    public static string ResolveTimelineState(string itemKey, string currentPhaseKey)
    {
        string[] phaseOrder = ["nomination", "voting", "preparation", "show"];
        if (string.Equals(currentPhaseKey, "completed", StringComparison.OrdinalIgnoreCase))
        {
            return phaseOrder.Contains(itemKey) ? "done" : "upcoming";
        }

        var itemIndex = Array.IndexOf(phaseOrder, itemKey);
        var currentIndex = Array.IndexOf(phaseOrder, currentPhaseKey);
        if (itemIndex < 0)
        {
            return "upcoming";
        }

        if (currentIndex < 0)
        {
            currentIndex = 0;
        }

        if (itemIndex < currentIndex)
        {
            return "done";
        }

        if (itemIndex == currentIndex)
        {
            return "active";
        }

        return "upcoming";
    }

    public static T[] DeserializeSiteArray<T>(string? json)
    {
        if (string.IsNullOrWhiteSpace(json))
        {
            return [];
        }

        try
        {
            return JsonSerializer.Deserialize<T[]>(
                json,
                new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? [];
        }
        catch
        {
            return [];
        }
    }

    public static PublicSocialLinkDto[] ReadSocialLinks(SiteSettings settings) =>
        DeserializeSiteArray<PublicSocialLinkDto>(settings.SocialLinksJson);

    public static FaqItemDto[] ReadFaqItems(SiteSettings settings) =>
        DeserializeSiteArray<FaqItemDto>(settings.FaqJson);

    public static FooterLinkDto[] BuildFooterLinks(SiteSettings settings) =>
    [
        new FooterLinkDto("imprint", "Impressum", settings.ImprintUrl, settings.ImprintContent),
        new FooterLinkDto("contact", "Kontakt", settings.ContactUrl, settings.ContactContent),
        new FooterLinkDto("sponsors", "Sponsoren & Partner", string.Empty, settings.SponsorsContent),
        new FooterLinkDto("showacts", "Showacts", settings.ShowactsUrl, settings.ShowactsContent),
    ];
}
