import type { RegexFlavourId } from "../model/flavour";

export interface ReferenceEntry {
  readonly id: string;
  readonly construct: string;
  readonly syntax: string;
  readonly explanation: string;
  readonly flavours: readonly RegexFlavourId[];
  readonly flags: readonly string[];
  readonly example: string;
  readonly caveat?: string;
  readonly source: string;
  readonly sourceUrl: string;
}

const ECMASCRIPT_REFERENCE_SOURCE =
  "https://tc39.es/ecma262/multipage/text-processing.html#sec-regexp-regular-expression-objects";

const ECMASCRIPT_REFERENCE_ENTRIES: readonly Omit<
  ReferenceEntry,
  "flavours" | "sourceUrl"
>[] = [
  {
    id: "literal",
    construct: "Literal",
    syntax: "text",
    explanation: "Matches the same sequence of characters.",
    flags: [],
    example: "invoice",
    source: "ECMAScript RegExp grammar",
  },
  {
    id: "any",
    construct: "Any character",
    syntax: ".",
    explanation:
      "Matches one character, excluding line terminators unless dotAll is active.",
    flags: ["s"],
    example: "a.b",
    source: "ECMAScript Atom grammar",
  },
  {
    id: "class",
    construct: "Character class",
    syntax: "[A-Z]",
    explanation: "Matches one character represented by the class.",
    flags: ["i", "u", "v"],
    example: "[A-F0-9]",
    source: "ECMAScript ClassRanges grammar",
  },
  {
    id: "capture",
    construct: "Capture group",
    syntax: "(...)",
    explanation: "Groups constructs and retains the matched substring.",
    flags: [],
    example: "(\\d{4})",
    source: "ECMAScript Grouping grammar",
  },
  {
    id: "named-capture",
    construct: "Named capture",
    syntax: "(?<name>...)",
    explanation:
      "Retains the matched substring under a stable name and number.",
    flags: [],
    example: "(?<year>\\d{4})",
    source: "ECMAScript NamedCapturingGroup grammar",
  },
  {
    id: "noncapture",
    construct: "Non-capturing group",
    syntax: "(?:...)",
    explanation: "Groups constructs without creating a capture.",
    flags: [],
    example: "(?:https?|ftp)",
    source: "ECMAScript GroupSpecifier grammar",
  },
  {
    id: "quantifier",
    construct: "Bounded repetition",
    syntax: "{min,max}",
    explanation: "Repeats the preceding construct between the selected bounds.",
    flags: [],
    example: "\\d{2,4}",
    source: "ECMAScript QuantifierPrefix grammar",
  },
  {
    id: "lookahead",
    construct: "Lookahead",
    syntax: "(?=...)",
    explanation: "Requires a following match without consuming it.",
    flags: [],
    example: "\\d+(?= EUR)",
    source: "ECMAScript Assertion grammar",
  },
  {
    id: "lookbehind",
    construct: "Lookbehind",
    syntax: "(?<=...)",
    explanation: "Requires a preceding match without consuming it.",
    flags: [],
    example: "(?<=€)\\d+",
    source: "ECMAScript Assertion grammar",
  },
  {
    id: "property",
    construct: "Unicode property",
    syntax: "\\p{Property}",
    explanation: "Matches characters with the selected Unicode property.",
    flags: ["u", "v"],
    example: "\\p{Letter}+",
    caveat: "Requires Unicode or Unicode-sets mode.",
    source: "ECMAScript UnicodePropertyValueExpression grammar",
  },
  {
    id: "backreference",
    construct: "Named backreference",
    syntax: "\\k<name>",
    explanation: "Matches the text retained by an earlier named capture.",
    flags: [],
    example: "(?<word>\\w+)\\s+\\k<word>",
    source: "ECMAScript AtomEscape grammar",
  },
  {
    id: "anchor",
    construct: "Input anchors",
    syntax: "^  $",
    explanation:
      "Assert the beginning or end of input; multiline mode also considers lines.",
    flags: ["m"],
    example: "^ERROR:.*$",
    source: "ECMAScript Assertion grammar",
  },
];

export const ECMASCRIPT_REFERENCE: readonly ReferenceEntry[] =
  ECMASCRIPT_REFERENCE_ENTRIES.map((entry) => ({
    ...entry,
    flavours: ["ecmascript"],
    sourceUrl: ECMASCRIPT_REFERENCE_SOURCE,
  }));

const PCRE2_REFERENCE_SOURCE =
  "https://www.pcre.org/current/doc/html/pcre2pattern.html";

export const PCRE2_REFERENCE: readonly ReferenceEntry[] = [
  {
    id: "pcre2-named-capture",
    construct: "Named capture",
    syntax: "(?<name>...)",
    explanation:
      "Captures under a number and name; PCRE2 also accepts (?'name'...) and (?P<name>...).",
    flavours: ["pcre2"],
    flags: [],
    example: "(?<year>\\d{4})",
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
  {
    id: "pcre2-branch-reset",
    construct: "Branch-reset group",
    syntax: "(?|...|...)",
    explanation:
      "Alternatives reuse the same capture numbers, which is useful for stable extraction schemas.",
    flavours: ["pcre2"],
    flags: [],
    example: "(?|(a)|(b))-(\\d+)",
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
  {
    id: "pcre2-atomic",
    construct: "Atomic group",
    syntax: "(?>...)",
    explanation: "Prevents backtracking into the group after it has matched.",
    flavours: ["pcre2"],
    flags: [],
    example: "(?>\\d+)\\d",
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
  {
    id: "pcre2-possessive",
    construct: "Possessive quantifier",
    syntax: "++  *+  ?+  {m,n}+",
    explanation:
      "Repeats without giving characters back during later backtracking.",
    flavours: ["pcre2"],
    flags: [],
    example: "\\w++:",
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
  {
    id: "pcre2-subroutine",
    construct: "Named subroutine",
    syntax: "(?&name)",
    explanation: "Invokes an earlier named group as a subpattern.",
    flavours: ["pcre2"],
    flags: [],
    example: "(?<pair>\\((?:[^()]|(?&pair))*\\))",
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
  {
    id: "pcre2-control-verb",
    construct: "Backtracking control",
    syntax: "(*SKIP)(*FAIL)",
    explanation:
      "Controls the engine search path; SKIP/FAIL is commonly used to exclude alternatives.",
    flavours: ["pcre2"],
    flags: [],
    example: '"[^"]*"(*SKIP)(*FAIL)|\\b\\w+\\b',
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
  {
    id: "pcre2-extended",
    construct: "Extended layout",
    syntax: "whitespace  # comment",
    explanation:
      "Ignores unescaped layout whitespace and enables line comments outside classes.",
    flavours: ["pcre2"],
    flags: ["x"],
    example: "(?<year>\\d{4})  # year",
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
  {
    id: "pcre2-unicode-property",
    construct: "Unicode property",
    syntax: "\\p{Property}",
    explanation:
      "Matches characters by Unicode property in the runtime's mandatory UTF/UCP mode.",
    flavours: ["pcre2"],
    flags: [],
    example: "\\p{L}+",
    caveat:
      "Regex Tools runs PCRE2 in UTF/UCP mode so native byte offsets always normalize safely to the browser editor.",
    source: "PCRE2 pattern documentation",
    sourceUrl: PCRE2_REFERENCE_SOURCE,
  },
];

const PYTHON_REFERENCE_SOURCE = "https://docs.python.org/3.14/library/re.html";

export const PYTHON_REFERENCE: readonly ReferenceEntry[] = [
  {
    id: "python-named-capture",
    construct: "Named capture",
    syntax: "(?P<name>...)",
    explanation:
      "Captures a group under both a number and a Python identifier.",
    flavours: ["python"],
    flags: [],
    example: "(?P<year>\\d{4})",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
  {
    id: "python-named-backreference",
    construct: "Named backreference",
    syntax: "(?P=name)",
    explanation: "Matches the text retained by an earlier named capture.",
    flavours: ["python"],
    flags: [],
    example: "(?P<quote>['\"]).*?(?P=quote)",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
  {
    id: "python-scoped-flags",
    construct: "Scoped inline flags",
    syntax: "(?aiLmsux-imsx:...)",
    explanation:
      "Applies selected matching modes only inside the enclosing group.",
    flavours: ["python"],
    flags: ["a", "i", "m", "s", "x"],
    example: "(?i:invoice)-(?a:\\w+)",
    caveat:
      "The a, L and u character-mode flags are mutually exclusive within one inline group.",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
  {
    id: "python-atomic",
    construct: "Atomic group",
    syntax: "(?>...)",
    explanation:
      "Discards the group's internal backtracking points after it succeeds.",
    flavours: ["python"],
    flags: [],
    example: "(?>\\d+)\\d",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
  {
    id: "python-possessive",
    construct: "Possessive quantifier",
    syntax: "*+  ++  ?+  {m,n}+",
    explanation:
      "Repeats without allowing later pattern parts to backtrack into the repetition.",
    flavours: ["python"],
    flags: [],
    example: "\\w++:",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
  {
    id: "python-lookbehind",
    construct: "Fixed-length lookbehind",
    syntax: "(?<=...)  (?<!...)",
    explanation:
      "Checks immediately preceding text without consuming it; the contained pattern must have a fixed length.",
    flavours: ["python"],
    flags: [],
    example: "(?<=€)\\d+",
    caveat:
      "Alternatives and repetitions are accepted only when the lookbehind still has one fixed width.",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
  {
    id: "python-conditional",
    construct: "Capture conditional",
    syntax: "(?(id/name)yes|no)",
    explanation:
      "Selects a branch according to whether an earlier capture participated.",
    flavours: ["python"],
    flags: [],
    example: "(<)?\\w+@(\\w+\\.)+\\w+(?(1)>|$)",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
  {
    id: "python-absolute-end",
    construct: "Absolute end anchor",
    syntax: "\\z",
    explanation: "Asserts the absolute end of the input.",
    flavours: ["python"],
    flags: [],
    example: "\\d+\\z",
    caveat: "The \\z spelling was added in Python 3.14.",
    source: "Python 3.14 re documentation",
    sourceUrl: PYTHON_REFERENCE_SOURCE,
  },
];

const JAVA_REFERENCE_SOURCE =
  "https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/regex/Pattern.html";

export const JAVA_REFERENCE: readonly ReferenceEntry[] = [
  {
    id: "java-named-capture",
    construct: "Named capture",
    syntax: "(?<name>...)",
    explanation:
      "Captures a group under both a number and a Latin-letter-led name.",
    flavours: ["java"],
    flags: [],
    example: "(?<year>\\d{4})",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-named-backreference",
    construct: "Named backreference",
    syntax: "\\k<name>",
    explanation: "Matches the text retained by an earlier named capture.",
    flavours: ["java"],
    flags: [],
    example: "(?<word>\\w+)\\s+\\k<word>",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-class-intersection",
    construct: "Character-class intersection",
    syntax: "[class&&class]",
    explanation:
      "Keeps only characters present in both nested character classes.",
    flavours: ["java"],
    flags: [],
    example: "[a-z&&[^aeiou]]+",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-scoped-flags",
    construct: "Scoped embedded flags",
    syntax: "(?idmsuxU-idmsuxU:...)",
    explanation: "Enables and disables selected Pattern modes for one group.",
    flavours: ["java"],
    flags: ["i", "d", "m", "s", "u", "x", "U"],
    example: "(?i:invoice)-(?-i:[A-Z]+)",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-independent",
    construct: "Independent group",
    syntax: "(?>...)",
    explanation:
      "Prevents the engine from revisiting choices made inside the group.",
    flavours: ["java"],
    flags: [],
    example: "(?>\\d+)\\d",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-possessive",
    construct: "Possessive quantifier",
    syntax: "*+  ++  ?+  {m,n}+",
    explanation:
      "Repeats without returning matched characters during later backtracking.",
    flavours: ["java"],
    flags: [],
    example: "\\w++:",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-linebreak",
    construct: "Unicode linebreak",
    syntax: "\\R",
    explanation:
      "Matches one Unicode linebreak sequence, including a CRLF pair as one sequence.",
    flavours: ["java"],
    flags: [],
    example: "^.+\\R.+$",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-grapheme",
    construct: "Extended grapheme cluster",
    syntax: "\\X",
    explanation:
      "Matches one extended Unicode grapheme cluster rather than one code point.",
    flavours: ["java"],
    flags: [],
    example: "\\X",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
  {
    id: "java-unicode-property",
    construct: "Unicode property",
    syntax: "\\p{Property}",
    explanation:
      "Matches characters selected by a supported Unicode category, script, block or binary property.",
    flavours: ["java"],
    flags: ["U"],
    example: "\\p{IsLatin}+",
    caveat:
      "The bundled TeaVM adapter reports compatibility warnings where its Pattern implementation differs from the documented Java SE language.",
    source: "Java SE 25 Pattern documentation",
    sourceUrl: JAVA_REFERENCE_SOURCE,
  },
];

export interface FlavourReference {
  readonly label: string;
  readonly entries: readonly ReferenceEntry[];
  readonly note?: string;
}

export const REFERENCE_BY_FLAVOUR: Readonly<
  Record<RegexFlavourId, FlavourReference>
> = {
  ecmascript: {
    label: "ECMAScript",
    entries: ECMASCRIPT_REFERENCE,
  },
  pcre2: {
    label: "PCRE2",
    entries: PCRE2_REFERENCE,
  },
  python: {
    label: "Python 3.14 re",
    entries: PYTHON_REFERENCE,
  },
  java: {
    label: "Java Pattern",
    entries: JAVA_REFERENCE,
    note: "This reference describes the Java Pattern language. The bundled TeaVM 0.15.0 adapter is a tested compatibility subset, not OpenJDK; replacement supports only single-digit $n references and not Java SE ${name}. Its diagnostics and engine metadata are authoritative for this build.",
  },
  pcre: {
    label: "PCRE",
    entries: [],
  },
  go: {
    label: "Go regexp",
    entries: [],
  },
  rust: {
    label: "Rust regex",
    entries: [],
  },
  dotnet: {
    label: ".NET Regex",
    entries: [],
  },
};
