from pydantic import ValidationError

from tktl.core.exceptions.exceptions import (
    MissingDocker,
    NoContentsFoundException,
    UserRepoValidationException,
)
from tktl.core.loggers import CliLogger
from tktl.core.managers.docker import DockerManager
from tktl.core.managers.project import ProjectManager
from tktl.core.schemas.project import ProjectValidationOutput
from tktl.core.validation.outputs import (
    ConfigFileValidationFailure,
    ProjectValidationFailure,
)

logger = CliLogger()


def validate_project_config(path: str):
    try:
        ProjectManager.validate_project_config(path)
    except ValidationError as e:
        validation_output = ProjectValidationOutput(
            title=ConfigFileValidationFailure.title,
            summary=ConfigFileValidationFailure.summary,
            text=ConfigFileValidationFailure.format_step_results(validation_errors=e),
        )
        log_failure(validation_output)
        return
    except (NoContentsFoundException, UserRepoValidationException) as e:
        validation_output = ProjectValidationOutput(
            title=ProjectValidationFailure.title,
            summary=ProjectValidationFailure.summary,
            text=ProjectValidationFailure.format_step_results(validation_errors=e),
        )
        log_failure(validation_output)
        return
    logger.log(f"Project scaffolding is valid!", color="green")


def log_failure(validation_output: ProjectValidationOutput):
    logger.log(
        f"Project scaffolding is invalid: {validation_output.title}", color="red"
    )
    logger.log(validation_output.summary, color="red", err=True)
    logger.log(validation_output.text, color="red", err=True)


def build_image(path: str):
    dm = DockerManager(path)

    logger.log("Patching docker file...")
    dm.patch_docker_file()
    logger.log("Building docker image...")
    image = dm.build_image()
    dm.remove_patched_docker_file()

    return dm, image


def status_output(status, logs):
    if status["StatusCode"] == 0:
        logger.log("Success", color="green")
    else:
        logger.log("Error", color="red")
        print(logs.decode())


def validate_import(path: str):
    try:
        dm, image = build_image(path)
        logger.log("Testing import of tktl...")
        status, logs = dm.test_import(image)
        status_output(status, logs)
    except MissingDocker:
        logger.log(
            "Couldn't locate docker, please make sure it is installed, or use the DOCKER_HOST environment variable",
            color="red",
        )


def validate_unittest(path: str):
    try:
        dm, image = build_image(path)
        logger.log("Running unittests...")
        status, logs = dm.test_unittest(image)
        status_output(status, logs)
    except MissingDocker:
        logger.log(
            "Couldn't locate docker, please make sure it is installed, or use the DOCKER_HOST environment variable",
            color="red",
        )


def validate_profiling(path: str):
    try:
        dm, image = build_image(path)
        logger.log("Running profiling (this can take a while)...")
        status, logs = dm.test_profiling(image)
        status_output(status, logs)
    except MissingDocker:
        logger.log(
            "Couldn't locate docker, please make sure it is installed, or use the DOCKER_HOST environment variable",
            color="red",
        )


def validate_integration(path: str):
    try:
        dm, image = build_image(path)
        logger.log("Waiting for service to start...")
        resp, output = dm.test_integration(image)

        if resp is None:
            logger.log("Could not access endpoint", color="red")
            print(output.decode())
        elif resp.status_code != 200:
            logger.log(f"Response status code {resp.status_code}", color="red")
            print(output.decode())
        else:
            logger.log("Success", color="green")

    except MissingDocker:
        logger.log(
            "Couldn't locate docker, please make sure it is installed, or use the DOCKER_HOST environment variable",
            color="red",
        )


def validate_all(path: str):
    validate_project_config(path)
    validate_import(path)
    validate_unittest(path)
    validate_profiling(path)
    validate_integration(path)
