import os.path
import sys
import dacite
from actions_logging.app_logging import logger
from aws.constants import ENVS
from github.env import exit_on_error_and_write_summary
import yaml
from dataclasses import dataclass
from typing import List
from yaml.resolver import Resolver

# this is an optional value to add to the env names in the workflow yaml file.
# in order to not choose an env by default
_SELECT_ENV = "select env"


@dataclass
class EnvNameOptions:
    type: str
    options: List[str]


@dataclass
class Inputs:
    ENV_NAME: EnvNameOptions


@dataclass
class WorkflowDispatch:
    inputs: Inputs


@dataclass
class On:
    workflow_dispatch: WorkflowDispatch


@dataclass
class WorkflowYAML:
    on: On


def validate_workflow(yaml_file):
    try:
        with open(yaml_file, 'r') as file:
            data = yaml.safe_load(file)
        workflow_data = dacite.from_dict(data_class=WorkflowYAML, data=data)
        sorted_env_names = sorted(workflow_data.on.workflow_dispatch.inputs.ENV_NAME.options)
        env_names_from_constants = list(ENVS.keys())
        env_names_from_constants.append(_SELECT_ENV)
        env_names_from_constants = sorted(env_names_from_constants)
        if sorted_env_names != env_names_from_constants:
            logger.warning(f"env names in workflow yaml file are not the same as in constants. {sorted_env_names}")
            input_envs = set(sorted_env_names)
            const_envs = set(env_names_from_constants)
            in_inputs_extra = input_envs - const_envs
            in_const_extra = const_envs - input_envs
            logger.warning(f"in inputs and not in consts: {list(in_inputs_extra)}")
            logger.warning(f"in consts and not in inputs: {list(in_const_extra)}")
            if not in_inputs_extra and in_const_extra == {_SELECT_ENV}:
                logger.warning(f"consider add '{_SELECT_ENV}' to your yaml and make it default")
                return True
            return False
        logger.info_green("env names inputs the same as they should be")
        return True
    except TypeError as e:
        exit_on_error_and_write_summary(f"yaml file empty: {e}")
    except dacite.exceptions.DaciteError as e:
        logger.warning(f"Schema validation error: {e}")
    except FileNotFoundError:
        exit_on_error_and_write_summary(f"workflow file not found: {yaml_file}")
    except Exception as e:
        exit_on_error_and_write_summary(f'unexpected error in check_yaml: {e}')


def parse_workflow_ref(workflow_ref):
    """
        "workflow_ref": "perimeter-81/p81-m3-scripts/.github/workflows/create_dev_package_and_deploy.yaml@main
    """
    try:
        workflow_path = workflow_ref.split("@")[0]
        path_prefix = ".github/workflows/"
        split_path = workflow_path.split(path_prefix)
        file_name = split_path[-1]
        workflow_path = os.path.join(path_prefix,file_name)
        return workflow_path
    except Exception as e:
        exit_on_error_and_write_summary(f"failed to parse workflow ref: {workflow_ref} the error is {e}")


def main():
    if not len(sys.argv) == 3:
        exit_on_error_and_write_summary(f"error - not 3 args. {sys.argv}")
    workflow_path = sys.argv[1].replace("workflow_path=", "", 1)
    workflow_ref = sys.argv[2].replace("workflow_ref=", "", 1)
    if not workflow_path:
        logger.warning(f"no workflow path in args. {workflow_path}")
        if not workflow_ref:
            exit_on_error_and_write_summary(f"no workflow ref: {workflow_ref}. or path in args. exiting")
        else:
            workflow_path = parse_workflow_ref(workflow_ref)
    validate_workflow(workflow_path)


if __name__ == '__main__':
    # remove resolver entries for On/Off/Yes/No
    for ch in "OoYyNn":
        if len(Resolver.yaml_implicit_resolvers[ch]) == 1:
            del Resolver.yaml_implicit_resolvers[ch]
        else:
            Resolver.yaml_implicit_resolvers[ch] = [x for x in
                                                    Resolver.yaml_implicit_resolvers[ch] if x[0] != 'tag:yaml.org,2002:bool']
    main()
