import pyparsing as pp


def search_parser(keys: dict[str, str]) -> pp.ParserElement:
    """Builds and returns a search query parser for simple key-value syntax."""
    value = pp.Word(pp.alphanums + "-_.") | pp.QuotedString('"') | pp.QuotedString("'")
    key = pp.oneOf(list(keys.keys()) + list(keys.values()))

    complete = pp.Group(key + pp.Suppress(":") + value)
    partial = pp.Group(key + pp.Suppress(":"))
    free_value = pp.Group(value)

    return pp.ZeroOrMore(complete | partial | free_value)


def parse_vuln_id(query: str) -> str | None:
    prefixes = ["CVE-", "OSV-", "GHSA-"]
    for p in prefixes:
        if p in query:
            start = query.find(p)
            if start != -1:
                rest = query[start:]
                return rest.split(" ")[0]
    return None


def parse_query(query: str, keys: dict[str, str]) -> dict[str, str]:
    """Parse a search query string into a structured dictionary."""
    parser = search_parser(keys)
    reverse_keys = {v: k for k, v in keys.items()}

    result: dict[str, str] = {key: "" for key in keys}

    for token in parser.parseString(query):
        if len(token) == 2:
            key, value = token

            if isinstance(value, str) and not value.strip():
                continue

            full_key = reverse_keys.get(key, key)
            if not result[full_key]:
                result[full_key] = value
        else:
            value = token[0]

            if isinstance(value, str) and not value.strip():
                continue

            first_key = next(iter(keys))
            if not result[first_key]:
                result[first_key] = value

    return result
