#!/usr/bin/env python3
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import re
from typing import List

# Preferred values for yes/no fields (i.e. all lowercase).
YES = "yes"
NO = "no"

# Pattern used to check if the entire string is "unknown",
# case-insensitive.
_PATTERN_UNKNOWN = re.compile(r"^unknown$", re.IGNORECASE)

# Pattern used to check if the entire string is functionally empty, i.e.
# empty string, or all characters are only whitespace.
_PATTERN_ONLY_WHITESPACE = re.compile(r"^\s*$")

# Pattern used to check if the string starts with "yes",
# case-insensitive.
_PATTERN_STARTS_WITH_YES = re.compile(r"^yes", re.IGNORECASE)

# Pattern used to check if the string starts with "no",
# case-insensitive.
_PATTERN_STARTS_WITH_NO = re.compile(r"^no", re.IGNORECASE)

# Variants of N/A (Not Applicable).
_PATTERN_NOT_APPLICABLE = re.compile(
    r"^(N ?\/ ?A)\.?|na\.?|not applicable\.?$", re.IGNORECASE
)

# A collection of values that provides little information.
# Use lower-case for easier comparison.
_KNOWN_INVALID_VALUES = {
    "0",
    "varies",
    "-",
    "unknown",
    "head",
    "see deps",
    "deps",
}


def matches(pattern: re.Pattern, value: str) -> bool:
    """Returns whether the value matches the pattern."""
    return pattern.match(value) is not None


def is_empty(value: str) -> bool:
    """Returns whether the value is functionally empty."""
    return matches(_PATTERN_ONLY_WHITESPACE, value)


def is_unknown(value: str) -> bool:
    """Returns whether the value is 'unknown' (case insensitive)."""
    return matches(_PATTERN_UNKNOWN, value)


def quoted(values: List[str]) -> str:
    """Returns a string of the given values, each being individually
    quoted.
    """
    return ", ".join([f"'{entry}'" for entry in values])


def infer_as_boolean(value: str, default: bool = True) -> bool:
    """Attempts to infer the value as a boolean, where:
    - "yes"-ish values return True;
    - "no"-ish values return False; and
    - default is returned otherwise.
    """
    if matches(_PATTERN_STARTS_WITH_YES, value):
        return True
    elif matches(_PATTERN_STARTS_WITH_NO, value):
        return False
    else:
        return default


def is_known_invalid_value(value: str):
    """Returns whether `value` is among the known bad values that provides
    little machine readable information.
    """
    if not value:
        return False

    if value.lower() in _KNOWN_INVALID_VALUES:
        return True

    return False


def is_not_applicable(value: str) -> bool:
    return matches(_PATTERN_NOT_APPLICABLE, value)
