"""Normalize only unambiguous raw multiline credentials inside legacy dotenv."""
import json
import re

MAX_INPUT_BYTES = 1024 * 1024
MAX_VALUE_BYTES = 512 * 1024
SPACE = r"[\t\v\f\r \x85\xa0]"
ASSIGNMENT = re.compile(
    SPACE + r"*(?:export" + SPACE + r"+)?[\w.\-\[\]](?:[\w.\-\[\]]|" + SPACE + r")*[=:]" + SPACE + "*"
)
PEM_START = re.compile(r"-----BEGIN ([A-Z][A-Z0-9 ]{0,63})-----\Z")
PEM_BODY = re.compile(r"[A-Za-z0-9+/]+={0,2}\Z")


class RuntimeEnvError(ValueError):
    """Only fixed, nonsecret reason codes may cross this boundary."""


def validate_text(text):
    try:
        size = len(text.encode("utf-8"))
    except (AttributeError, UnicodeError):
        raise RuntimeEnvError("runtime_env_text_invalid") from None
    if size > MAX_INPUT_BYTES:
        raise RuntimeEnvError("runtime_env_input_limit")
    if "\x00" in text:
        raise RuntimeEnvError("runtime_env_text_invalid")


def quoted_end(text, start):
    quote, escaped = text[start], False
    for index in range(start + 1, len(text)):
        char = text[index]
        if char == quote and not escaped:
            return index + 1
        escaped = char == "\\" and not escaped
        if index - start > MAX_VALUE_BYTES:
            raise RuntimeEnvError("runtime_env_value_limit")
    raise RuntimeEnvError("runtime_env_quote_invalid")


def unique_pairs(items):
    result = {}
    for key, value in items:
        if key in result:
            raise RuntimeEnvError("runtime_env_json_invalid")
        result[key] = value
    return result


def reject_constant(value):
    raise RuntimeEnvError("runtime_env_json_invalid")


def json_end(text, start):
    stack, quoted, escaped = [], False, False
    for index in range(start, len(text)):
        char = text[index]
        if quoted:
            if char == '"' and not escaped:
                quoted = False
            escaped = char == "\\" and not escaped
        elif char == '"':
            quoted = True
        elif char in "[{":
            stack.append(char)
            if len(stack) > 64:
                raise RuntimeEnvError("runtime_env_json_invalid")
        elif char in "]}":
            if not stack or stack.pop() != ("[" if char == "]" else "{"):
                raise RuntimeEnvError("runtime_env_json_invalid")
            if not stack:
                value = text[start:index + 1]
                if "\n" in value:
                    try:
                        json.loads(value, object_pairs_hook=unique_pairs, parse_constant=reject_constant)
                    except (ValueError, RecursionError):
                        raise RuntimeEnvError("runtime_env_json_invalid") from None
                return index + 1
        if index - start > MAX_VALUE_BYTES:
            raise RuntimeEnvError("runtime_env_value_limit")
    raise RuntimeEnvError("runtime_env_json_invalid")


def pem_end(text, start):
    first_end = text.find("\n", start)
    match = PEM_START.fullmatch(text[start:first_end].rstrip("\r")) if first_end >= 0 else None
    if not match:
        raise RuntimeEnvError("runtime_env_pem_invalid")
    marker, position, lines = "-----END " + match[1] + "-----", first_end + 1, 0
    while position < len(text):
        end = text.find("\n", position)
        end = len(text) if end < 0 else end
        line = text[position:end].rstrip("\r")
        if line.startswith(marker):
            if not lines:
                raise RuntimeEnvError("runtime_env_pem_invalid")
            return position + len(marker)
        if not PEM_BODY.fullmatch(line):
            raise RuntimeEnvError("runtime_env_pem_invalid")
        lines += 1
        position = end + 1
        if position - start > MAX_VALUE_BYTES:
            raise RuntimeEnvError("runtime_env_value_limit")
    raise RuntimeEnvError("runtime_env_pem_invalid")


def statement_end(text, end):
    boundary = text.find("\n", end)
    boundary = len(text) if boundary < 0 else boundary
    tail = text[end:boundary]
    if tail.strip() and not (tail[:1].isspace() and tail.lstrip().startswith("#")):
        raise RuntimeEnvError("runtime_env_structure_ambiguous")
    return boundary


def unassigned_line(line):
    candidate = line.lstrip()
    if candidate and not candidate.startswith("#") and not re.fullmatch(r"[\w.\-\[\]\s]+", candidate):
        raise RuntimeEnvError("runtime_env_statement_invalid")


def literal(value):
    if len(value.encode("utf-8")) > MAX_VALUE_BYTES:
        raise RuntimeEnvError("runtime_env_value_limit")
    return "'" + value.replace("'", "\\'") + "'"


def normalize(text):
    validate_text(text)
    output, cursor, copied = [], 1 if text.startswith("\ufeff") else 0, 0
    while cursor < len(text):
        line_end = text.find("\n", cursor)
        line_end = len(text) if line_end < 0 else line_end
        match = ASSIGNMENT.match(text, cursor)
        if not match:
            line = text[cursor:line_end]
            if line.lstrip().startswith(("-----BEGIN ", "-----END ")):
                raise RuntimeEnvError("runtime_env_structure_ambiguous")
            unassigned_line(line)
            cursor = line_end + 1
            continue
        start, end = match.end(), line_end
        first = text[start:line_end].strip()
        if first.startswith(("'", '"')):
            end = quoted_end(text, start)
            statement_end(text, end)
        elif first.startswith("-----BEGIN "):
            end = pem_end(text, start)
        elif re.match(r'\{\s*(?:"|$)|\[\s*(?:[\[\{"0-9-]|true|false|null|$)', first):
            end = json_end(text, start)
        if len(text[start:end].encode("utf-8")) > MAX_VALUE_BYTES:
            raise RuntimeEnvError("runtime_env_value_limit")
        if end > line_end and text[start:start + 1] not in ("'", '"'):
            statement_end(text, end)
            output.extend((text[copied:start], literal(text[start:end])))
            copied = end
        cursor = text.find("\n", end) + 1
        if not cursor:
            break
    output.append(text[copied:])
    result = "".join(output)
    validate_text(result)
    return result
