import os
import re
import sys

import yaml

from actions_logging.app_logging import logger
from github.env import (exit_on_error_and_write_summary,
                        halt_or_continue_on_error, parse_bool_env_var)


def read_workflow_file(file_path):
    try:
        logger.info(f"trying to read workflow yaml from {file_path}")
        with open(file_path, 'r') as file:
            data = yaml.safe_load(file)
            logger.info(f"successfully read workflow file")
            jobs = data.get('jobs')
            if not jobs:
                exit_on_error_and_write_summary("no jobs specified for workflow")
            return data
    except Exception as e:
        exit_on_error_and_write_summary(f"An error occurred during reading workflow yaml from path {file_path}: {e}")

def validate_comma_separated_list(value):
    """Checks if value provided is a comma separated list of works like word1,word2,... word2 and later are optional"""
    pattern = r'^[^,\s]+(,[^,\s]+)*$'
    if re.match(pattern, value):
        return True
    return False

def parse_job_names_in_workflow(workflow, job_names):
    logger.info(f"parsing JOB_NAMES {job_names} to a python list of job names")
    if not job_names:
        return []
    if not validate_comma_separated_list(job_names):
        exit_on_error_and_write_summary("bad JOB_NAMES list provided, it should be a comma separated list of job names in the workflow")
    job_names_list = job_names.split(',')
    validate_all_job_names_in_workflow(workflow, job_names_list)
    return job_names_list

def get_jobs_with_key_from_workflow(workflow, key, job_names):
    jobs_with_key = []
    jobs_to_search = []
    jobs =  workflow.get('jobs')
    if not job_names:
        jobs_to_search = jobs
    else:
        jobs_to_search = {job_name:job for job_name, job in jobs.items() if job_name in job_names}
    for existing_job_name, job in jobs_to_search.items():
        if key in job.keys():
            jobs_with_key.append((existing_job_name, job))
    logger.info(f"jobs with {key} found")
    return jobs_with_key

def check_key_value_in_all_jobs(jobs, key, value):
    matched = all(job.get(key) == value for job in jobs)
    return matched


def validate_all_job_names_in_workflow(workflow, job_names):
    exisiting_job_names = [ job_name for job_name in workflow.get('jobs', {}).keys()]
    if not exisiting_job_names:
        exit_on_error_and_write_summary("no jobs defined in workflow")
    for job_name in job_names:
        if job_name not in exisiting_job_names:
            exit_on_error_and_write_summary(f"Job name '{job_name}' of provided ones not found among existing job names in the workflow: {', '.join(exisiting_job_names)}")

def main():
    workflow_path = str(os.getenv("WORKFLOW_PATH"))
    key = str(os.getenv("KEY"))
    job_names = os.getenv("JOB_NAMES", '')
    halt_workflow = parse_bool_env_var(os.getenv("HALT_WORKFLOW", True))
    value = str(os.getenv("VALUE", ''))

    if not workflow_path:
        exit_on_error_and_write_summary("workflow path missing")
    if not key:
        exit_on_error_and_write_summary("key is missing")

    logger.info(f"workflow_path: {workflow_path}")
    logger.info(f"key: {key}")
    logger.info(f"job_names: {job_names}")
    logger.info(f"halt_workflow: {halt_workflow}")
    logger.info(f"value: {value}" )

    workflow = read_workflow_file(workflow_path)
    job_names_list = parse_job_names_in_workflow(workflow, job_names)
    all_workflow_jobs_names = [name for name in workflow.get('jobs').keys()]
    jobs_with_key_tuple = get_jobs_with_key_from_workflow(workflow, key, job_names_list)
    # this is because of job's schema
    jobs_names_with_key = [ name for name,_ in jobs_with_key_tuple ]
    jobs_with_key = [ job for _, job in jobs_with_key_tuple ]

    if job_names_list and len(job_names_list) != len(jobs_names_with_key):
        halt_or_continue_on_error(f"Key {key} not found in all workflow's provided jobs {job_names}", halt_workflow)

    if not job_names_list and len(all_workflow_jobs_names) != len(jobs_names_with_key):
        halt_or_continue_on_error(f"Key {key} not found in all workflow's jobs", halt_workflow)

    if not value:
        logger.info(f"key {key} found in workflow jobs: {', '.join(jobs_names_with_key)}, workflow continues...")
        sys.exit(0)

    value_found_in_all_jobs_with_key = check_key_value_in_all_jobs(jobs_with_key, key, value)

    if not value_found_in_all_jobs_with_key:
        halt_or_continue_on_error(f"key/value pair {key}/{value} not found in workflow's jobs", halt_workflow)

    logger.info(f"key/value pair {key}: {value} found in {', '.join(jobs_names_with_key)} jobs, workflow continues...")

if __name__ == "__main__":
    main()
