#!/usr/bin/env python3
"""Generate synthetic inputs and candidate tests from a learned CARBON flow."""

from __future__ import annotations

import argparse
import json
import re
from collections import deque
from pathlib import Path
from typing import Any

KINDS = {"web", "api", "mixed"}
INPUT_TYPES = {
    "text",
    "username",
    "password",
    "email",
    "url",
    "phone",
    "integer",
    "number",
    "currency",
    "percent",
    "boolean",
    "enum",
    "date",
    "datetime",
    "json",
    "file",
}
MAX_STATES = 128
MAX_TRANSITIONS = 512
MAX_INPUTS = 128
MAX_ACTORS = 64
MAX_ENUM_VALUES = 256


def slug(value: str) -> str:
    result = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
    return result[:48] or "flow"


def require_text(value: Any, field: str) -> str:
    if not isinstance(value, str) or not value.strip():
        raise ValueError(f"{field} requires non-empty text")
    return value.strip()


def text_list(value: Any, field: str) -> list[str]:
    if value is None:
        return []
    if not isinstance(value, list) or not all(
        isinstance(item, str) and item.strip() for item in value
    ):
        raise ValueError(f"{field} must be an array of non-empty strings")
    return [item.strip() for item in value]


def normalize_spec(raw: dict[str, Any]) -> dict[str, Any]:
    if not isinstance(raw, dict):
        raise ValueError("Flow specification must be a JSON object")
    flow_id = require_text(raw.get("id"), "id")
    if not re.fullmatch(r"[A-Za-z0-9._:-]+", flow_id):
        raise ValueError(f"Invalid flow id: {flow_id!r}")
    kind = str(raw.get("kind", "")).lower()
    if kind not in KINDS:
        raise ValueError("kind must be web, api, or mixed")
    states = text_list(raw.get("states"), "states")
    if len(states) < 2 or len(states) != len(set(states)):
        raise ValueError("states must contain at least two unique values")
    if len(states) > MAX_STATES:
        raise ValueError(f"states exceeds the safe limit of {MAX_STATES}")
    initial = require_text(raw.get("initialState"), "initialState")
    if initial not in states:
        raise ValueError("initialState must name a declared state")
    terminals = text_list(raw.get("terminalStates"), "terminalStates")
    unknown_terminals = sorted(set(terminals) - set(states))
    if unknown_terminals:
        raise ValueError(f"Unknown terminal states: {unknown_terminals}")

    transitions_raw = raw.get("transitions")
    if not isinstance(transitions_raw, list) or not transitions_raw:
        raise ValueError("transitions must contain at least one transition")
    if len(transitions_raw) > MAX_TRANSITIONS:
        raise ValueError(
            f"transitions exceeds the safe limit of {MAX_TRANSITIONS}"
        )
    transitions: list[dict[str, Any]] = []
    transition_ids: set[str] = set()
    for index, item in enumerate(transitions_raw, start=1):
        if not isinstance(item, dict):
            raise ValueError(f"transitions[{index}] must be an object")
        transition_id = require_text(item.get("id"), f"transitions[{index}].id")
        if not re.fullmatch(r"[A-Za-z0-9._:-]+", transition_id):
            raise ValueError(f"Invalid transition id: {transition_id!r}")
        if transition_id in transition_ids:
            raise ValueError(f"Duplicate transition id: {transition_id}")
        transition_ids.add(transition_id)
        before = require_text(item.get("from"), f"{transition_id}.from")
        after = require_text(item.get("to"), f"{transition_id}.to")
        if before not in states or after not in states:
            raise ValueError(f"{transition_id} references an unknown state")
        transitions.append(
            {
                "id": transition_id,
                "from": before,
                "action": require_text(item.get("action"), f"{transition_id}.action"),
                "to": after,
                "oracle": require_text(item.get("oracle"), f"{transition_id}.oracle"),
                "guard": str(item.get("guard", "")).strip(),
                "sideEffect": bool(item.get("sideEffect", False)),
                "reversible": bool(item.get("reversible", True)),
            }
        )

    inputs_raw = raw.get("inputs", [])
    if not isinstance(inputs_raw, list):
        raise ValueError("inputs must be an array")
    if len(inputs_raw) > MAX_INPUTS:
        raise ValueError(f"inputs exceeds the safe limit of {MAX_INPUTS}")
    inputs: list[dict[str, Any]] = []
    input_names: set[str] = set()
    for index, item in enumerate(inputs_raw, start=1):
        if not isinstance(item, dict):
            raise ValueError(f"inputs[{index}] must be an object")
        name = require_text(item.get("name"), f"inputs[{index}].name")
        if name in input_names:
            raise ValueError(f"Duplicate input name: {name}")
        input_names.add(name)
        input_type = str(item.get("type", "text")).lower()
        if input_type not in INPUT_TYPES:
            raise ValueError(f"Unsupported input type for {name}: {input_type}")
        minimum = item.get("min")
        maximum = item.get("max")
        if minimum is not None and not isinstance(minimum, (int, float)):
            raise ValueError(f"{name}.min must be numeric")
        if maximum is not None and not isinstance(maximum, (int, float)):
            raise ValueError(f"{name}.max must be numeric")
        if minimum is not None and maximum is not None and minimum > maximum:
            raise ValueError(f"{name}.min must not exceed max")
        enum = text_list(item.get("enum"), f"{name}.enum")
        if len(enum) > MAX_ENUM_VALUES:
            raise ValueError(
                f"{name}.enum exceeds the safe limit of {MAX_ENUM_VALUES}"
            )
        if input_type == "enum" and not enum:
            raise ValueError(f"{name}.enum requires at least one value")
        inputs.append(
            {
                "name": name,
                "type": input_type,
                "required": bool(item.get("required", False)),
                "min": minimum,
                "max": maximum,
                "format": str(item.get("format", "")).strip(),
                "enum": enum,
                "sensitive": bool(item.get("sensitive", False)),
            }
        )

    actors_raw = raw.get("actors", [])
    if not isinstance(actors_raw, list):
        raise ValueError("actors must be an array")
    if len(actors_raw) > MAX_ACTORS:
        raise ValueError(f"actors exceeds the safe limit of {MAX_ACTORS}")
    actors: list[dict[str, Any]] = []
    actor_ids: set[str] = set()
    for index, item in enumerate(actors_raw, start=1):
        if not isinstance(item, dict):
            raise ValueError(f"actors[{index}] must be an object")
        actor_id = require_text(item.get("id"), f"actors[{index}].id")
        if actor_id in actor_ids:
            raise ValueError(f"Duplicate actor id: {actor_id}")
        actor_ids.add(actor_id)
        actors.append(
            {
                "id": actor_id,
                "role": require_text(item.get("role"), f"{actor_id}.role"),
                "authorized": bool(item.get("authorized", True)),
            }
        )

    return {
        "id": flow_id,
        "title": require_text(raw.get("title"), "title"),
        "kind": kind,
        "outcome": require_text(raw.get("outcome"), "outcome"),
        "actors": actors,
        "preconditions": text_list(raw.get("preconditions"), "preconditions"),
        "initialState": initial,
        "terminalStates": terminals,
        "states": states,
        "transitions": transitions,
        "inputs": inputs,
        "sideEffects": text_list(raw.get("sideEffects"), "sideEffects"),
        "cleanup": text_list(raw.get("cleanup"), "cleanup"),
        "stalenessAnchors": text_list(
            raw.get("stalenessAnchors"), "stalenessAnchors"
        ),
    }


def generated(length: int, character: str = "a") -> dict[str, Any]:
    return {"generator": "repeat", "value": character, "length": max(0, length)}


def add_fixture(
    fixtures: list[dict[str, Any]],
    field: dict[str, Any],
    category: str,
    value: Any,
    expected: str,
    rationale: str,
) -> None:
    fixtures.append(
        {
            "id": f"DATA-{slug(field['name']).upper()}-{len(fixtures) + 1:03d}",
            "field": field["name"],
            "inputType": field["type"],
            "category": category,
            "value": value,
            "expected": expected,
            "rationale": rationale,
            "sensitive": field["sensitive"],
        }
    )


def fixtures_for(field: dict[str, Any]) -> list[dict[str, Any]]:
    fixtures: list[dict[str, Any]] = []
    input_type = field["type"]
    minimum = field["min"]
    maximum = field["max"]
    valid = "accept"
    reject = "reject safely"

    if input_type in {"integer", "number", "currency", "percent"}:
        baseline = minimum if minimum is not None else 1
        add_fixture(fixtures, field, "valid", baseline, valid, "ordinary valid value")
        values: list[tuple[str, Any]] = [("zero", 0), ("negative", -1)]
        if minimum is not None:
            values.extend(
                [
                    ("below-min", minimum - 1),
                    ("at-min", minimum),
                    ("above-min", minimum + 1),
                ]
            )
        if maximum is not None:
            values.extend(
                [
                    ("below-max", maximum - 1),
                    ("at-max", maximum),
                    ("above-max", maximum + 1),
                ]
            )
        if input_type != "integer":
            values.append(("fractional", 1.5))
        values.extend([("wrong-type", "one"), ("null", None)])
        seen: set[str] = set()
        for category, value in values:
            marker = json.dumps(value, sort_keys=True)
            if marker in seen:
                continue
            seen.add(marker)
            in_range = (
                isinstance(value, (int, float))
                and (minimum is None or value >= minimum)
                and (maximum is None or value <= maximum)
            )
            add_fixture(
                fixtures,
                field,
                category,
                value,
                valid if in_range else reject,
                "numeric type and boundary coverage",
            )
        return fixtures

    if input_type == "boolean":
        for category, value, expected in [
            ("true", True, valid),
            ("false", False, valid),
            ("null", None, reject if field["required"] else valid),
            ("wrong-type", "true", reject),
        ]:
            add_fixture(
                fixtures, field, category, value, expected, "boolean coercion coverage"
            )
        return fixtures

    if input_type == "enum":
        for value in field["enum"]:
            add_fixture(fixtures, field, "declared", value, valid, "declared enum value")
        add_fixture(
            fixtures, field, "unknown", "__unknown__", reject, "unknown enum member"
        )
        add_fixture(
            fixtures,
            field,
            "case-variant",
            field["enum"][0].swapcase(),
            "follow the observed case contract",
            "enum case sensitivity",
        )
        add_fixture(
            fixtures,
            field,
            "null",
            None,
            reject if field["required"] else valid,
            "nullability",
        )
        return fixtures

    valid_by_type: dict[str, Any] = {
        "username": "carbon.tester",
        "password": "Correct-Horse-Carbon-42!",
        "email": "carbon.tester@example.test",
        "url": "https://example.test/carbon",
        "phone": "+1-202-555-0142",
        "date": "2026-07-28",
        "datetime": "2026-07-28T12:34:56Z",
        "json": {"name": "carbon", "enabled": True},
        "file": {
            "name": "carbon-test.txt",
            "mediaType": "text/plain",
            "bytes": 12,
        },
        "text": "CARBON test",
    }
    invalid_by_type: dict[str, Any] = {
        "username": "a",
        "password": "password",
        "email": "not-an-email",
        "url": "not a url",
        "phone": "call-me",
        "date": "2026-02-30",
        "datetime": "not-a-datetime",
        "json": "{not-json",
        "file": {"name": "empty.bin", "mediaType": "application/octet-stream", "bytes": 0},
        "text": "",
    }
    add_fixture(
        fixtures,
        field,
        "valid",
        valid_by_type[input_type],
        valid,
        "ordinary synthetic value",
    )
    add_fixture(
        fixtures,
        field,
        "empty",
        "",
        reject if field["required"] else "accept or preserve optional semantics",
        "empty value",
    )
    add_fixture(
        fixtures,
        field,
        "null",
        None,
        reject if field["required"] else valid,
        "nullability",
    )
    add_fixture(
        fixtures,
        field,
        "invalid-format",
        invalid_by_type[input_type],
        reject,
        "format validation",
    )

    if input_type in {
        "text",
        "username",
        "password",
        "email",
        "url",
        "phone",
    }:
        for category, value, rationale in [
            ("whitespace", "   ", "blank-equivalent handling"),
            ("unicode", "Jalapeño 東京", "international text"),
            ("emoji", "carbon🧪", "supplementary Unicode"),
            ("emoticon", "carbon:-)", "ASCII punctuation sequence"),
            ("rtl", "كربون", "right-to-left text"),
            ("combining", "e\u0301", "Unicode normalization"),
            ("markup-like", "<b>carbon</b>", "safe encoding and display"),
        ]:
            add_fixture(
                fixtures,
                field,
                category,
                value,
                "follow the observed field contract without corruption or execution",
                rationale,
            )
        if isinstance(minimum, (int, float)):
            for delta, category in [(-1, "below-min"), (0, "at-min"), (1, "above-min")]:
                length = max(0, int(minimum) + delta)
                add_fixture(
                    fixtures,
                    field,
                    category,
                    generated(length),
                    valid if delta >= 0 else reject,
                    f"exact length {length}",
                )
        if isinstance(maximum, (int, float)):
            for delta, category in [(-1, "below-max"), (0, "at-max"), (1, "above-max")]:
                length = max(0, int(maximum) + delta)
                add_fixture(
                    fixtures,
                    field,
                    category,
                    generated(length),
                    valid if delta <= 0 else reject,
                    f"exact length {length}",
                )
    return fixtures


def shortest_path(flow: dict[str, Any]) -> list[dict[str, Any]]:
    terminals = set(flow["terminalStates"])
    if not terminals:
        return []
    queue: deque[tuple[str, list[dict[str, Any]]]] = deque(
        [(flow["initialState"], [])]
    )
    visited = {flow["initialState"]}
    while queue:
        state, path = queue.popleft()
        if state in terminals and path:
            return path
        for transition in flow["transitions"]:
            if transition["from"] != state or transition["to"] in visited:
                continue
            visited.add(transition["to"])
            queue.append((transition["to"], [*path, transition]))
    return []


def generate_flow_pack(
    raw: dict[str, Any],
    *,
    session_id: str,
    target: str,
    environment: str,
    revision: str,
) -> dict[str, Any]:
    flow = normalize_spec(raw)
    fixtures = [
        fixture for field in flow["inputs"] for fixture in fixtures_for(field)
    ]
    flow_key = flow["id"].upper()
    for fixture in fixtures:
        fixture["id"] = f"DATA-{flow_key}-{fixture['id'].removeprefix('DATA-')}"
    adapter = {
        "web": "isolated-browser",
        "api": "direct-http",
        "mixed": "isolated-browser+direct-http",
    }[flow["kind"]]
    flags = {
        "destructive": False,
        "costly": False,
        "privacy": any(item["sensitive"] for item in flow["inputs"]),
        "payment": any("payment" in value.lower() for value in flow["sideEffects"]),
        "notification": any(
            "notif" in value.lower() or "message" in value.lower()
            for value in flow["sideEffects"]
        ),
        "security": False,
    }
    cases: list[dict[str, Any]] = []

    def add_case(
        title: str,
        *,
        priority: str,
        case_type: str,
        steps: list[str],
        oracle: str,
        reason: str,
        data: list[str] | None = None,
        provenance: list[str] | None = None,
        local_flags: dict[str, bool] | None = None,
        seconds: int = 60,
    ) -> None:
        case_flags = dict(flags)
        case_flags.update(local_flags or {})
        cases.append(
            {
                "id": f"LF-{flow_key}-{len(cases) + 1:03d}",
                "title": title,
                "priority": priority,
                "type": case_type,
                "flow": flow["title"],
                "item": "learned flow",
                "reason": reason,
                "provenance": [
                    f"learning-session:{session_id}",
                    f"learned-flow:{flow['id']}",
                    *(provenance or []),
                ],
                "prerequisites": flow["preconditions"],
                "data": data or [],
                "steps": steps,
                "oracle": oracle,
                "estimatedSeconds": seconds,
                "dependencies": [],
                "parallelGroup": f"learned-{slug(flow['id'])}",
                "adapter": adapter,
                "flags": case_flags,
                "learningStatus": "candidate",
            }
        )

    path = shortest_path(flow)
    if path:
        add_case(
            "Complete the discovered canonical path",
            priority="P0",
            case_type="learned flow · canonical",
            steps=[
                f"Start in state {flow['initialState']}",
                *[
                    f"{item['action']} ({item['from']} → {item['to']})"
                    for item in path
                ],
            ],
            oracle=flow["outcome"],
            reason="The shortest observed route to a terminal outcome is the core promise.",
            data=[fixture["id"] for fixture in fixtures if fixture["category"] == "valid"],
            provenance=[f"transition:{item['id']}" for item in path],
            local_flags={
                "destructive": any(not item["reversible"] for item in path)
            },
            seconds=max(60, len(path) * 30),
        )

    for transition in flow["transitions"]:
        add_case(
            f"Transition {transition['from']} → {transition['to']}: {transition['action']}",
            priority="P1" if transition["reversible"] else "P0",
            case_type="learned flow · transition",
            steps=[
                f"Arrange state {transition['from']}",
                transition["action"],
                "Observe state and downstream effects before cleanup",
            ],
            oracle=transition["oracle"],
            reason="Every discovered transition needs direct behavioral coverage.",
            provenance=[f"transition:{transition['id']}"],
            local_flags={"destructive": not transition["reversible"]},
        )
        wrong_state = next(
            (
                state
                for state in flow["states"]
                if state not in {transition["from"], transition["to"]}
            ),
            flow["initialState"] if flow["initialState"] != transition["from"] else "",
        )
        if wrong_state:
            add_case(
                f"Reject {transition['action']} from state {wrong_state}",
                priority="P1",
                case_type="learned flow · forbidden transition",
                steps=[
                    f"Arrange state {wrong_state}",
                    f"Attempt {transition['action']}",
                ],
                oracle=(
                    f"The action is unavailable or rejected safely; state remains {wrong_state}; "
                    "no unauthorized side effect occurs."
                ),
                reason="State machines often fail at forbidden or stale transitions.",
                provenance=[f"transition:{transition['id']}", f"wrong-state:{wrong_state}"],
                local_flags={"security": True},
            )
        if transition["guard"]:
            add_case(
                f"Enforce guard for {transition['action']}",
                priority="P1",
                case_type="learned flow · guard",
                steps=[
                    f"Arrange state {transition['from']}",
                    f"Make guard false: {transition['guard']}",
                    f"Attempt {transition['action']}",
                ],
                oracle="The transition is rejected safely with actionable feedback and no side effect.",
                reason="Guard conditions are common AI-generated-code branch gaps.",
                provenance=[f"transition:{transition['id']}", "guard:false"],
            )

    for fixture in fixtures:
        priority = (
            "P1"
            if fixture["category"]
            in {"empty", "null", "below-min", "above-max", "invalid-format"}
            else "P2"
        )
        add_case(
            f"{fixture['field']}: {fixture['category']} input",
            priority=priority,
            case_type="learned flow · generated input",
            steps=[
                f"Reach the first state that accepts {fixture['field']}",
                f"Supply generated fixture {fixture['id']}",
                "Attempt the next reversible transition and inspect stored/returned value",
            ],
            oracle=(
                f"Candidate oracle: {fixture['expected']}; preserve state integrity, encode output "
                "safely, and provide actionable feedback when rejected."
            ),
            reason=fixture["rationale"],
            data=[fixture["id"]],
            provenance=[f"input:{fixture['field']}", f"fixture:{fixture['id']}"],
            local_flags={"privacy": fixture["sensitive"]},
            seconds=45,
        )

    for actor in flow["actors"]:
        if actor["authorized"]:
            continue
        add_case(
            f"Prevent unauthorized {actor['role']} from completing the flow",
            priority="P0",
            case_type="learned flow · authorization",
            steps=[
                f"Use synthetic actor {actor['id']} with role {actor['role']}",
                "Attempt each reachable state-changing transition",
            ],
            oracle="Access is denied consistently at the UI and service boundary with no data or side-effect leakage.",
            reason="Discovered flows must test role and ownership boundaries.",
            data=[f"actor:{actor['id']}"],
            provenance=[f"actor:{actor['id']}"],
            local_flags={"security": True},
            seconds=90,
        )

    shared_cases = [
        (
            "Retry a state-changing transition",
            "P1",
            ["Reach a state-changing transition", "Trigger it twice or retry after an ambiguous response"],
            "At most one intended effect occurs; the final state and feedback are coherent.",
            "retry and idempotency",
        ),
        (
            "Interrupt and resume the flow",
            "P1",
            ["Advance to an intermediate state", "Interrupt safely", "Resume or reopen the flow"],
            "The flow resumes at a coherent state or explains that recovery is unavailable without corrupting data.",
            "interruption and recovery",
        ),
        (
            "Refresh or reconnect from an intermediate state",
            "P2",
            ["Advance to an intermediate state", "Refresh or reconnect", "Inspect persisted and transient values"],
            "Persistence follows the discovered contract; no duplicate action or silent data loss occurs.",
            "persistence",
        ),
        (
            "Resolve concurrent or stale state",
            "P1",
            ["Open the same synthetic record in two isolated views", "Advance one view", "Act from the stale view"],
            "The target detects or safely resolves stale state without overwriting newer data silently.",
            "concurrency and stale state",
        ),
        (
            "Cancel and clean up synthetic flow data",
            "P1",
            ["Start the flow with synthetic data", "Cancel before final commit", *flow["cleanup"]],
            "Cancellation and cleanup leave no unintended durable record or external effect.",
            "cleanup and reversibility",
        ),
    ]
    for title, priority, steps, oracle, reason in shared_cases:
        add_case(
            title,
            priority=priority,
            case_type=f"learned flow · {reason}",
            steps=steps,
            oracle=oracle,
            reason=f"Automatically generated {reason} coverage for the learned state graph.",
            seconds=90,
        )

    if flow["kind"] in {"web", "mixed"}:
        add_case(
            "Complete the flow with keyboard and assistive semantics",
            priority="P1",
            case_type="learned flow · accessibility",
            steps=[
                "Use only keyboard navigation through the flow",
                "Inspect names, roles, states, focus, errors, and announcements",
            ],
            oracle="Every action is operable; focus is visible and logical; labels, state changes, errors, and completion are perceivable.",
            reason="Custom learned flows commonly hide accessibility failures.",
            seconds=120,
        )
        add_case(
            "Preserve the flow across responsive layouts and history",
            priority="P2",
            case_type="learned flow · navigation",
            steps=[
                "Advance on narrow and wide isolated viewports",
                "Use back and forward where applicable",
            ],
            oracle="Controls and state remain reachable and coherent without accidental duplicate submission.",
            reason="Layout and browser history can alter a discovered flow.",
            seconds=120,
        )

    if flow["kind"] in {"api", "mixed"}:
        add_case(
            "Reject malformed and unsupported protocol shapes",
            priority="P1",
            case_type="learned flow · API contract",
            steps=[
                "Vary required fields, types, content type, version, and unknown fields one at a time",
                "Capture status, error envelope, headers, and side effects",
            ],
            oracle="Invalid requests fail consistently without server errors, partial mutation, or sensitive disclosure.",
            reason="The learned API contract needs transport-level negative coverage.",
            local_flags={"security": True},
            seconds=120,
        )
        add_case(
            "Reach and recover from API terminal failures",
            priority="P1",
            case_type="learned flow · API recovery",
            steps=[
                "Exercise a bounded timeout, cancellation, or documented failure path",
                "Poll, reconnect, or retry according to the discovered protocol",
            ],
            oracle="Terminal conditions are unambiguous; recovery is bounded; partial results and cleanup follow the contract.",
            reason="Asynchronous APIs often omit end, retry, or cancellation conditions.",
            seconds=120,
        )

    return {
        "schemaVersion": 1,
        "generatedFrom": "learned-flow",
        "learningSession": session_id,
        "target": target,
        "environment": environment,
        "revision": revision,
        "flow": flow,
        "inputs": fixtures,
        "cases": cases,
        "candidateNotice": (
            "Generated cases and oracles are planned hypotheses until execution produces evidence."
        ),
    }


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--spec", required=True)
    parser.add_argument("--output", required=True)
    parser.add_argument("--session-id", required=True)
    parser.add_argument("--target", default="")
    parser.add_argument("--environment", default="local isolated test environment")
    parser.add_argument("--revision", default="")
    args = parser.parse_args()
    try:
        raw = json.loads(Path(args.spec).read_text(encoding="utf-8"))
        pack = generate_flow_pack(
            raw,
            session_id=args.session_id,
            target=args.target,
            environment=args.environment,
            revision=args.revision,
        )
        output = Path(args.output).expanduser().resolve()
        output.parent.mkdir(parents=True, exist_ok=True)
        output.write_text(json.dumps(pack, indent=2, ensure_ascii=False) + "\n")
        print(output)
        return 0
    except (OSError, ValueError, json.JSONDecodeError) as error:
        print(f"carbon_flowgen: {error}")
        return 2


if __name__ == "__main__":
    raise SystemExit(main())
