"""Validate manifests."""

import argparse
from pathlib import Path
import subprocess
import sys

from script.util import valid_integration

from . import docs, error, gather_info, generate
from .model import Info

TEMPLATES = [
    p.name for p in (Path(__file__).parent / "templates").glob("*") if p.is_dir()
]


def get_arguments() -> argparse.Namespace:
    """Get parsed passed in arguments."""
    parser = argparse.ArgumentParser(description="Home Assistant Scaffolder")
    parser.add_argument("template", type=str, choices=TEMPLATES)
    parser.add_argument(
        "--develop", action="store_true", help="Automatically fill in info"
    )
    parser.add_argument(
        "--integration", type=valid_integration, help="Integration to target."
    )

    return parser.parse_args()


def run_process(name: str, cmd: list[str], info: Info) -> None:
    """Run a sub process and handle the result.

    :param name: The name of the sub process used in reporting.
    :param cmd: The sub process arguments.
    :param info: The Info object.
    :raises subprocess.CalledProcessError: If the subprocess failed.

    If the sub process was successful print a success message, otherwise
    print an error message and raise a subprocess.CalledProcessError.
    """
    print(f"Command: {' '.join(cmd)}")
    print()
    result: subprocess.CompletedProcess = subprocess.run(cmd, check=False)
    if result.returncode == 0:
        print()
        print(f"Completed {name} successfully.")
        print()
        return

    print()
    print(f"Fatal Error: {name} failed with exit code {result.returncode}")
    print()
    if info.is_new:
        print("This is a bug, please report an issue!")
    else:
        print(
            "This may be an existing issue with your integration,",
            "if so fix and run `script.scaffold` again,",
            "otherwise please report an issue.",
        )
    result.check_returncode()


def main() -> int:
    """Scaffold an integration."""
    if not Path("requirements_all.txt").is_file():
        print("Run from project root")
        return 1

    args = get_arguments()

    info = gather_info.gather_info(args)
    print()

    # If we are calling scaffold on a non-existing integration,
    # We're going to first make it. If we're making an integration,
    # we will also make a config flow to go with it.

    if info.is_new:
        generate.generate("integration", info)

        # If it's a new integration and it's not a config flow,
        # create a config flow too.
        if not args.template.startswith("config_flow"):
            if info.helper:
                template = "config_flow_helper"
            elif info.oauth2:
                template = "config_flow_oauth2"
            elif info.authentication or not info.discoverable:
                template = "config_flow"
            else:
                template = "config_flow_discovery"

            generate.generate(template, info)

    # If we wanted a new integration, we've already done our work.
    if args.template != "integration":
        generate.generate(args.template, info)

    # Always output sub commands as the output will contain useful information if a command fails.
    print("Running hassfest to pick up new information.")
    run_process(
        "hassfest",
        [
            "python",
            "-m",
            "script.hassfest",
            "--integration-path",
            str(info.integration_dir),
            "--skip-plugins",
            "quality_scale",  # Skip quality scale as it will fail for newly generated integrations.
        ],
        info,
    )

    print("Running gen_requirements_all to pick up new information.")
    run_process(
        "gen_requirements_all",
        ["python", "-m", "script.gen_requirements_all"],
        info,
    )

    print("Running translations to pick up new translation strings.")
    run_process(
        "translations",
        [
            "python",
            "-m",
            "script.translations",
            "develop",
            "--integration",
            info.domain,
        ],
        info,
    )

    if args.develop:
        print("Running tests")
        run_process(
            "pytest",
            [
                "python3",
                "-b",
                "-m",
                "pytest",
                "-vvv",
                f"tests/components/{info.domain}",
            ],
            info,
        )

    docs.print_relevant_docs(args.template, info)

    return 0


if __name__ == "__main__":
    try:
        sys.exit(main())
    except subprocess.CalledProcessError as err:
        sys.exit(err.returncode)
    except error.ExitApp as err:
        print()
        print(f"Fatal Error: {err.reason}")
        sys.exit(err.exit_code)