using System.Collections.Generic;
using System.Linq;

namespace TestersAI;

/// <summary>
/// Check-type enum + tester roster + token resolver. Pass a mix of
/// <see cref="CheckType"/>, alias strings, tester first-name keys,
/// <see cref="Tester"/>s, or <see cref="CustomTester"/>s into the
/// <c>checks</c> / <c>testers</c> parameters on any analyze call.
/// </summary>
public static class Checks
{
    public enum CheckType
    {
        Accessibility, Security, Privacy, Performance, Usability,
        Content, Forms, Search, Publishing, LandingPage,
        Checkout, Cart, Pricing, ErrorUx, AiCode, AiChatbot
    }

    public static string Wire(CheckType c) => c switch
    {
        CheckType.Accessibility => "accessibility",
        CheckType.Security      => "security",
        CheckType.Privacy       => "privacy",
        CheckType.Performance   => "performance",
        CheckType.Usability     => "usability",
        CheckType.Content       => "content",
        CheckType.Forms         => "forms",
        CheckType.Search        => "search",
        CheckType.Publishing    => "publishing",
        CheckType.LandingPage   => "landing_page",
        CheckType.Checkout      => "checkout",
        CheckType.Cart          => "cart",
        CheckType.Pricing       => "pricing",
        CheckType.ErrorUx       => "error_ux",
        CheckType.AiCode        => "ai_code",
        CheckType.AiChatbot     => "ai_chatbot",
        _ => c.ToString().ToLowerInvariant(),
    };

    public static readonly IReadOnlyDictionary<string, CheckType> Aliases = new Dictionary<string, CheckType>
    {
        ["a11y"] = CheckType.Accessibility,
        ["ally"] = CheckType.Accessibility,
        ["wcag"] = CheckType.Accessibility,
        ["sec"] = CheckType.Security,
        ["appsec"] = CheckType.Security,
        ["owasp"] = CheckType.Security,
        ["perf"] = CheckType.Performance,
        ["web_vitals"] = CheckType.Performance,
        ["ux"] = CheckType.Usability,
        ["copy"] = CheckType.Content,
        ["spelling"] = CheckType.Content,
        ["seo"] = CheckType.Content,
        ["form"] = CheckType.Forms,
        ["landing"] = CheckType.LandingPage,
        ["ecommerce"] = CheckType.Checkout,
        ["payment"] = CheckType.Checkout,
        ["gdpr"] = CheckType.Privacy,
        ["ccpa"] = CheckType.Privacy,
        ["pii"] = CheckType.Privacy,
        ["chatbot"] = CheckType.AiChatbot,
        ["vibe_coding"] = CheckType.AiCode,
        ["errors"] = CheckType.ErrorUx,
    };

    public sealed class Tester
    {
        public string Key { get; }
        public string Name { get; }
        public string Role { get; }
        public string Focus { get; }
        public IReadOnlyList<CheckType> Checks { get; }
        public Tester(string k, string n, string r, string f, params CheckType[] c)
        { Key = k; Name = n; Role = r; Focus = f; Checks = c; }
    }

    public static readonly IReadOnlyList<Tester> Testers = new[]
    {
        new Tester("sharon",    "Sharon",    "Security Tester",          "OWASP Top 10",     CheckType.Security),
        new Tester("marcus",    "Marcus",    "OWASP Security",           "AppSec",           CheckType.Security),
        new Tester("mia",       "Mia",       "Usability Expert",         "UX Heuristics",    CheckType.Usability),
        new Tester("alejandro", "Alejandro", "Accessibility Specialist", "WCAG 2.2 AA",      CheckType.Accessibility),
        new Tester("hiroshi",   "Hiroshi",   "WCAG Compliance",          "WCAG AAA",         CheckType.Accessibility),
        new Tester("pete",      "Pete",      "Privacy Analyst",          "GDPR / CCPA",      CheckType.Privacy),
        new Tester("zanele",    "Zanele",    "GDPR Specialist",          "EU Privacy",       CheckType.Privacy),
        new Tester("rajesh",    "Rajesh",    "Cookie Consent Tester",    "Cookie Law",       CheckType.Privacy),
        new Tester("sundar",    "Sundar",    "Legal Policy Reviewer",    "Legal Compliance", CheckType.Privacy),
        new Tester("jason",     "Jason",     "GenAI Code Reviewer",      "Vibe Coding",      CheckType.AiCode),
        new Tester("diego",     "Diego",     "AI Chatbot Tester",        "Conversational AI",CheckType.AiChatbot),
        new Tester("tariq",     "Tariq",     "Performance Engineer",     "Core Vitals",      CheckType.Performance),
        new Tester("fatima",    "Fatima",    "Error Message Analyst",    "Error UX",         CheckType.ErrorUx),
        new Tester("sophia",    "Sophia",    "Content Quality Auditor", "Content QA",        CheckType.Content),
        new Tester("richard",   "Richard",   "Forms Specialist",         "Form UX",          CheckType.Forms),
        new Tester("mei",       "Mei",       "Search Box Tester",        "Search UX",        CheckType.Search),
        new Tester("zara",      "Zara",      "News & Content",           "Publishing QA",    CheckType.Publishing),
        new Tester("yuki",      "Yuki",      "Landing Page Analyst",     "Conversion QA",    CheckType.LandingPage),
        new Tester("hassan",    "Hassan",    "Checkout Tester",          "E-commerce",       CheckType.Checkout),
        new Tester("priya",     "Priya",     "Shopping Cart Tester",     "Cart Flows",       CheckType.Cart),
        new Tester("mateo",     "Mateo",     "Pricing Page Tester",      "SaaS Pricing",     CheckType.Pricing),
    };

    public static readonly IReadOnlyDictionary<string, Tester> TestersByKey =
        Testers.ToDictionary(t => t.Key);

    /// <summary>Custom tester definition — evaluated alongside the built-ins.</summary>
    public sealed class CustomTester
    {
        public string Name { get; set; } = "";
        public string Role { get; set; } = "";
        public string Instructions { get; set; } = "";
        public string Focus { get; set; } = "custom";
        public IReadOnlyList<string> Tags { get; set; } = System.Array.Empty<string>();
        public IReadOnlyList<CheckType> CheckTypes { get; set; } = System.Array.Empty<CheckType>();

        internal IDictionary<string, object?> ToWire() => new Dictionary<string, object?>
        {
            ["custom"] = true,
            ["name"] = Name,
            ["role"] = Role,
            ["focus"] = Focus,
            ["instructions"] = Instructions,
            ["tags"] = Tags.ToList(),
            ["checks"] = CheckTypes.Select(Wire).ToList(),
        };
    }

    public sealed class Resolved
    {
        public List<string> Checks { get; } = new();
        public List<string> Testers { get; } = new();
        public List<IDictionary<string, object?>> CustomTesters { get; } = new();
        public List<object> Unknown { get; } = new();
    }

    public static Resolved Resolve(IEnumerable<object>? tokens)
    {
        var r = new Resolved();
        if (tokens is null) return r;
        var seenC = new HashSet<string>();
        var seenT = new HashSet<string>();
        foreach (var tok in tokens)
        {
            if (tok is CustomTester ct) { r.CustomTesters.Add(ct.ToWire()); continue; }
            if (tok is CheckType c)     { var w = Wire(c); if (seenC.Add(w)) r.Checks.Add(w); continue; }
            if (tok is Tester t)        { if (seenT.Add(t.Key)) r.Testers.Add(t.Key); continue; }
            if (tok is string s)
            {
                var k = s.Trim().ToLowerInvariant().Replace(' ', '_').Replace('-', '_');
                var match = System.Enum.GetValues<CheckType>().FirstOrDefault(v => Wire(v) == k);
                if (System.Enum.IsDefined(typeof(CheckType), match) && Wire(match) == k)
                {
                    if (seenC.Add(k)) r.Checks.Add(k); continue;
                }
                if (Aliases.TryGetValue(k, out var alias))
                {
                    var w = Wire(alias); if (seenC.Add(w)) r.Checks.Add(w); continue;
                }
                if (TestersByKey.ContainsKey(k))
                {
                    if (seenT.Add(k)) r.Testers.Add(k); continue;
                }
            }
            r.Unknown.Add(tok);
        }
        return r;
    }
}
