import os
import yaml
import yamale
from yamale.validators import Validator, DefaultValidators
from pathlib import Path


class StepValidator(Validator):
    tag = "step"

    def _is_valid(self, value):
        action_fields = {
            "commit_file": {
                "required": [],
                "optional": ["auto_commit", "commit_msg", "repository"],
            },
            "workflow_monitor": {
                "required": ["workflow_name"],
                "optional": ["show_workflow"],
            },
            "approve_pull_request": {
                "required": ["source_branch", "target_branch"],
                "optional": [],
            },
        }

        action = value.get("action")
        if not action:
            self._errors.append("O campo 'action' é obrigatório.")
            return False

        if action not in action_fields:
            self._errors.append(f"A ação '{action}' não é reconhecida.")
            return False

        required_fields = action_fields[action]["required"]
        optional_fields = action_fields[action]["optional"]
        allowed_fields = set(required_fields + optional_fields + ["action"])

        missing_fields = [field for field in required_fields if field not in value]
        if missing_fields:
            self._errors.append(
                f"Campos obrigatórios ausentes para a ação '{action}': {', '.join(missing_fields)}."
            )
            return False

        unexpected_fields = [field for field in value if field not in allowed_fields]
        if unexpected_fields:
            self._errors.append(
                f"Campos inesperados para a ação '{action}': {', '.join(unexpected_fields)}."
            )
            return False

        return True

    def fail(self, value):
        return " ".join(self._errors)


def config_validator(base_dir: str) -> bool:
    """
    Valida um arquivo YAML contra um esquema definido.

    Args:
        base_dir (str): Base dir.

    Returns:
        bool: True se o arquivo for válido, False caso contrário.
    """
    config_path = os.path.join(base_dir, ".config.yml")
    utils_base_dir = os.path.dirname(os.path.abspath(__file__))
    schema_path = os.path.join(utils_base_dir, "schema.yml")

    try:
        with open(config_path, "r", encoding="utf-8") as f:
            content = f.read()
        data = yamale.make_data(content=content)
        validators = DefaultValidators.copy()
        validators[StepValidator.tag] = StepValidator
        schema = yamale.make_schema(schema_path, validators=validators)
        yamale.validate(schema, data)
        return True
    except FileNotFoundError:
        print(f"Erro: Arquivo de configuração não encontrado em: {config_path}")
        return False
    except yamale.YamaleError as exc:
        print(".config.yml não é válido:")
        for result in exc.results:
            for error in result.errors:
                print(f"  - {error}")
        return False
    except Exception as e:
        print(f"Ocorreu um erro inesperado durante a validação: {e}")
        return False


def check_config_name():
    config_files = ["config.yml", "config.yaml"]
    config_file = None

    for file in config_files:
        if os.path.exists(os.path.join(os.getcwd(), file)):
            config_file = file
            break

    if config_file is None:
        raise FileNotFoundError(
            "Config file not founded (.config.yml ou .config.yaml)."
        )

    return config_file


def load_config(config_file: Path) -> dict:
    """
    Load the configuration from the YAML file.

    Returns:
        dict: The loaded configuration.
    """
    # print("Getting config file...")

    config_path = os.path.join(os.getcwd(), config_file)

    with open(config_path, "r", encoding="utf-8") as f:
        try:
            config = yaml.safe_load(f)
            # print(f"Load configuration with success!")
            return config
        except FileNotFoundError:
            print(
                f"Aviso: arquivo config.yml não encontrado em: {os.getcwd()}. Usando configurações padrão (se houver)."
            )
            return {}
        except yaml.YAMLError as e:
            print(f"Erro ao ler o arquivo config.yml: {e}")
            return {}


def get_task(task_name: str, config_file: Path) -> dict:
    """
    Load the configuration from the YAML file and return the task details.

    Args:
        task_name (str): The name of the task to retrieve.

    Returns:
        dict: The task details.
    """
    # print("Getting task parameters...")
    try:
        config = load_config(config_file)
        task = config["tasks"].get(task_name)
        if task != None:
            return task
        else:
            raise KeyError(f"Task '{task_name}' not founded.")
    except KeyError as exc:  # Verificar: esta é a mensagem de erro correta?
        print(f"Error getting desired task: {exc}")
        raise
