import os
import re
import subprocess
from collections import defaultdict

from actions_logging.app_logging import logger
from env_files.utils import get_high_env_file_paths
from github.env import get_required_env_var
from github.github_apis import get_changed_files
from master.get_changed_content_level import get_change_level
from slack_wrapper.slack_notifier import main as send_slack_message


def get_key_name(input_string):
    """
    Extract key name from the change string.
    """
    match = re.search(r"'(.*?)'", input_string)
    if match:
        return match.group(1)
    return None


def check_env_alignment(pr_number, repo_name):
    """
    Check environment files (production, staging, etc.) for key-level changes and alignments.
    """
    try:
        logger.debug(f"Fetching changed files for PR #{pr_number} in repository {repo_name}")
        pr_changes = get_changed_files(repo_name, pr_number)
        is_multi_service_repo = os.getenv("IS_MULTI_SERVICE_REPO", "false") == "true"
        svc_name = ""
        if is_multi_service_repo:
            svc_name = get_required_env_var("SVC_NAME")
            logger.info(f"Multi-service repo detected, service name: {svc_name}")

        env_file_paths = get_high_env_file_paths(svc_name)
        human_readable_changes = defaultdict(set)
        key_change_occurrences = defaultdict(list)

        # Iterate over changed files and check for relevant environment files
        for filename in pr_changes:
            file_path = filename["filename"]
            if file_path in env_file_paths:
                if not filename.get("patch"):
                    continue
                _, changes_by_key = get_change_level(filename["patch"])

                for change in changes_by_key:
                    key_name = get_key_name(change)
                    if key_name:
                        # Find the corresponding environment key by matching the file_path
                        env_key = env_file_paths[file_path]
                        human_readable_changes[env_key].add(key_name)
                        key_change_occurrences[key_name].append(env_key)
        logger.debug(f"Human readable changes: {human_readable_changes}")
        logger.debug(f"Key change occurrences: {key_change_occurrences}")
        # Generate messages for environments with changes
        misalignment_messages = []
        for key, envs in key_change_occurrences.items():
            # If the key is changed in some but not all environments, trigger an alert
            missing_envs = set(env_file_paths.values()) - set(envs)
            if missing_envs:
                misalignment_messages.append(
                    f"Key '{key}' changed in environment: {', '.join(envs)}, but didn't change in: {', '.join(missing_envs)}."
                )

        if misalignment_messages:
            full_message = "\n".join(misalignment_messages)
            logger.debug(f"Misalignment detected, sending Slack notification: {full_message}")
            send_slack_notification(full_message)

        return len(misalignment_messages) > 0

    except Exception as e:
        logger.error(f"Error during environment alignment check: {e}")
        return True


def send_slack_notification(message):
    """Send a Slack notification using slack_notifier.py."""
    try:
        # Set the environment variables required by slack_notifier.py
        os.environ["SLACK_STATUS"] = "WARNING"
        os.environ["SLACK_MESSAGE"] = message
        os.environ["SLACK_CHANNEL"] = get_required_env_var("SLACK_CHANNEL")
        os.environ["SLACK_TITLE"] = "Environment Misalignment Detected"
        os.environ["SLACK_TOKEN"] = get_required_env_var("GLOBAL_CICD_SLACK_TOKEN")
        os.environ["SLACK_USERNAME"] = get_required_env_var("SLACK_USERNAME")

        send_slack_message()
    except subprocess.CalledProcessError as e:
        logger.error(f"Error sending Slack notification: {e}")


def main():
    try:
        repo_name = get_required_env_var("GITHUB_REPOSITORY")
        pr_number = get_required_env_var("PR_NUMBER")
        logger.info(f"repo_name: {repo_name}, pr_number: {pr_number}")

        # Check if environments are aligned in terms of keys
        misaligned = check_env_alignment(pr_number, repo_name)

        if not misaligned:
            logger.info_green_bg("All environments are aligned in terms of keys.")
    except Exception as e:
        logger.error(f"Error in unaligned_env_changes.main: {e}")


if __name__ == "__main__":
    main()
