package ai.testers;

import java.util.*;

/**
 * Check-type enum + tester roster + token resolver. Mirrors the Python /
 * JavaScript {@code checks} modules. Users pass any mix of {@link CheckType},
 * alias strings, tester first-name keys, or {@link CustomTester} instances
 * to {@code TestersAI#analyze*} via the {@code checks} and {@code testers}
 * lists; {@link #resolve(List)} normalises them for the wire.
 */
public final class Checks {
    private Checks() {}

    public enum CheckType {
        ACCESSIBILITY("accessibility"),
        SECURITY("security"),
        PRIVACY("privacy"),
        PERFORMANCE("performance"),
        USABILITY("usability"),
        CONTENT("content"),
        FORMS("forms"),
        SEARCH("search"),
        PUBLISHING("publishing"),
        LANDING_PAGE("landing_page"),
        CHECKOUT("checkout"),
        CART("cart"),
        PRICING("pricing"),
        ERROR_UX("error_ux"),
        AI_CODE("ai_code"),
        AI_CHATBOT("ai_chatbot");

        public final String wire;
        CheckType(String w) { this.wire = w; }
    }

    public static final Map<String, CheckType> ALIASES = Map.ofEntries(
        Map.entry("a11y", CheckType.ACCESSIBILITY),
        Map.entry("ally", CheckType.ACCESSIBILITY),
        Map.entry("wcag", CheckType.ACCESSIBILITY),
        Map.entry("sec", CheckType.SECURITY),
        Map.entry("appsec", CheckType.SECURITY),
        Map.entry("owasp", CheckType.SECURITY),
        Map.entry("perf", CheckType.PERFORMANCE),
        Map.entry("web_vitals", CheckType.PERFORMANCE),
        Map.entry("ux", CheckType.USABILITY),
        Map.entry("copy", CheckType.CONTENT),
        Map.entry("spelling", CheckType.CONTENT),
        Map.entry("seo", CheckType.CONTENT),
        Map.entry("form", CheckType.FORMS),
        Map.entry("landing", CheckType.LANDING_PAGE),
        Map.entry("ecommerce", CheckType.CHECKOUT),
        Map.entry("payment", CheckType.CHECKOUT),
        Map.entry("gdpr", CheckType.PRIVACY),
        Map.entry("ccpa", CheckType.PRIVACY),
        Map.entry("pii", CheckType.PRIVACY),
        Map.entry("chatbot", CheckType.AI_CHATBOT),
        Map.entry("vibe_coding", CheckType.AI_CODE),
        Map.entry("errors", CheckType.ERROR_UX)
    );

    public static final class Tester {
        public final String key, name, role, focus;
        public final List<CheckType> checks;
        Tester(String key, String name, String role, String focus, CheckType... cs) {
            this.key = key; this.name = name; this.role = role; this.focus = focus;
            this.checks = List.of(cs);
        }
    }

    public static final List<Tester> TESTERS = List.of(
        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.AI_CODE),
        new Tester("diego",     "Diego",     "AI Chatbot Tester",        "Conversational AI", CheckType.AI_CHATBOT),
        new Tester("tariq",     "Tariq",     "Performance Engineer",     "Core Vitals",       CheckType.PERFORMANCE),
        new Tester("fatima",    "Fatima",    "Error Message Analyst",    "Error UX",          CheckType.ERROR_UX),
        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.LANDING_PAGE),
        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 final Map<String, Tester> TESTERS_BY_KEY;
    static {
        Map<String, Tester> m = new HashMap<>();
        for (Tester t : TESTERS) m.put(t.key, t);
        TESTERS_BY_KEY = Collections.unmodifiableMap(m);
    }

    public static final class CustomTester {
        public String name, role, instructions, focus = "custom";
        public List<String> tags = List.of();
        public List<CheckType> checks = List.of();
        public CustomTester(String name, String role, String instructions) {
            this.name = name; this.role = role; this.instructions = instructions;
        }
        Map<String, Object> toWire() {
            Map<String, Object> m = new LinkedHashMap<>();
            m.put("custom", true); m.put("name", name); m.put("role", role);
            m.put("focus", focus); m.put("instructions", instructions);
            m.put("tags", tags);
            List<String> cs = new ArrayList<>();
            for (CheckType c : checks) cs.add(c.wire);
            m.put("checks", cs);
            return m;
        }
    }

    /** Return value: {@code checks}, {@code testers}, {@code custom_testers}, {@code unknown}. */
    public static final class Resolved {
        public final List<String> checks = new ArrayList<>();
        public final List<String> testers = new ArrayList<>();
        public final List<Map<String, Object>> customTesters = new ArrayList<>();
        public final List<Object> unknown = new ArrayList<>();
    }

    public static Resolved resolve(List<Object> tokens) {
        Resolved r = new Resolved();
        Set<String> seenC = new HashSet<>(), seenT = new HashSet<>();
        if (tokens == null) return r;
        for (Object tok : tokens) {
            if (tok instanceof CustomTester) {
                r.customTesters.add(((CustomTester) tok).toWire());
                continue;
            }
            if (tok instanceof CheckType) {
                String v = ((CheckType) tok).wire;
                if (seenC.add(v)) r.checks.add(v);
                continue;
            }
            if (tok instanceof Tester) {
                String v = ((Tester) tok).key;
                if (seenT.add(v)) r.testers.add(v);
                continue;
            }
            if (tok instanceof String) {
                String k = ((String) tok).trim().toLowerCase().replace(' ', '_').replace('-', '_');
                CheckType byVal = null;
                for (CheckType c : CheckType.values()) if (c.wire.equals(k)) { byVal = c; break; }
                if (byVal != null) {
                    if (seenC.add(byVal.wire)) r.checks.add(byVal.wire);
                    continue;
                }
                CheckType alias = ALIASES.get(k);
                if (alias != null) {
                    if (seenC.add(alias.wire)) r.checks.add(alias.wire);
                    continue;
                }
                if (TESTERS_BY_KEY.containsKey(k)) {
                    if (seenT.add(k)) r.testers.add(k);
                    continue;
                }
            }
            r.unknown.add(tok);
        }
        return r;
    }
}
