import os

from lambdas.constants import DEFAULT_NODE_VERSION
from actions_logging.app_logging import logger
from aws.constants import STG_PROD_ENVS, STAGING, PRODUCTION, PROD_ENVS
from aws.env_info import get_env_bucket
from env_files.build_and_upload_dotenv import copy_versioned_dot_env_to_root, backup_dot_env
from aws.s3_apis.s3 import upload_file_to_s3
from env_files.constants import VERSION_HISTORY_FOLDER, DEV_BRANCH_VERSION_MESSAGE, VERSION_HISTORY_FILE, VERSION_SUFFIX, DEFAULT_ENV_FILES_PATH
from env_files.create_dot_env import create_dot_env_from_json
from env_files.version_history import (
    set_current_env_vars_version,
    add_version_history_record,
    get_env_version_from_history,
    VersionHistoryRecord
)
from env_files.rebuild import rebuild_and_upload_dot_env
from env_files.utils import get_multi_service_repo, get_svc_env_files_for_env_level, route_core_ecs
from git.utils import get_current_branch, get_dev_version
from github.env import get_required_env_var, exit_on_error_and_write_summary, write_github_env


def create_and_upload_dot_env_for_dev_version(env_name: str, svc_name: str, is_multi_service_repo: bool, env_files_path: str = DEFAULT_ENV_FILES_PATH):
    try:
        bucket_name = get_env_bucket(env_name)
        dot_env_name = f"{svc_name}.env"
        create_dot_env_from_json(source_json_path=None,
                                 env_name=env_name,
                                 svc_name=svc_name,
                                 is_multi_service_repo=is_multi_service_repo,
                                 base_env_files_path=env_files_path)
        upload_file_to_s3(bucket_name=bucket_name, file_name=dot_env_name)
        os.remove(dot_env_name)
    except Exception as e:
        exit_on_error_and_write_summary(f"couldn't create and update env vars in s3 file while building dev version due to error: {e}")


def update_env_history_for_dev_version(env_name: str,
                                       svc_name: str,
                                       dev_version: str,
                                       is_multi_service_repo: bool,
                                       version_history_folder: str = VERSION_HISTORY_FOLDER) -> str:
    try:
        # if this is a hotfix build, we need to tag the repo with the env vars dev version for service upon deployment success
        git_env_version = None
        if dev_version and (dev_version.startswith(STAGING) or dev_version.startswith(PRODUCTION)):
            git_env_version = dev_version
        branch = get_current_branch()
        vh_record = VersionHistoryRecord(
            env_version=dev_version,
            branch=branch,
            git_version=git_env_version,
            message=DEV_BRANCH_VERSION_MESSAGE,
        )
        logger.debug(f'vh_record: {vh_record}')
        version_history_path_extend = env_name
        if is_multi_service_repo:
            version_history_path_extend = os.path.join(svc_name, env_name)
        add_version_history_record(vh_record, version_history_path_extend, version_history_folder)

        return git_env_version
    except Exception as e:
        exit_on_error_and_write_summary(f"couldn't update env vars file while building dev version due to error: {e}")

def get_svc_prod_env_names(svc_name: str, is_multi_service_repo: bool) -> list[str]:
    env_files = get_svc_env_files_for_env_level(svc_name, is_multi_service_repo, PRODUCTION)
    return [os.path.basename(env_file).split('.')[0] for env_file in env_files]


@route_core_ecs
def handle_dot_env_and_history_update(env_name: str,
                                      svc_name: str,
                                      git_env_version: str,
                                      rebuild_env_file: bool,
                                      is_multi_service_repo: bool,
                                      version_history_folder: str = VERSION_HISTORY_FOLDER,
                                      env_files_path: str = DEFAULT_ENV_FILES_PATH) -> tuple[str, str]:
    logger.info_green(f"updating env vars file for {svc_name} in {env_name}")
    history_env_version = "" # history env version is not the same as git_env_version but it can be == dev version
    dev_version = ""
    dot_env_name = f"{svc_name}.env"

    bucket_name = get_env_bucket(env_name)
    backup_dot_env(env_name, dot_env_name)

    if git_env_version:
        version_history_path = os.path.join(version_history_folder, env_name, VERSION_HISTORY_FILE)
        if is_multi_service_repo:
            version_history_path = os.path.join(version_history_folder, svc_name, env_name, VERSION_HISTORY_FILE)
        history_env_version = get_env_version_from_history(version_history_path, git_env_version)
        logger.info_green(f"env version for {git_env_version} is {history_env_version} (received from version history)")

    if not rebuild_env_file and git_env_version:
        logger.info_yellow("env file git version provided and no rebuild flag provided, will just copy the versioned .env to the root of the bucket")
        copy_versioned_dot_env_to_root(history_env_version, bucket_name, svc_name)
    elif rebuild_env_file and git_env_version:
        logger.info_yellow("env file git version provided and rebuild flag provided, will rebuild current .env version, upload it to s3 versioned folder and copy it to the root of the bucket")
        rebuild_and_upload_dot_env(git_env_version, svc_name, env_name, is_multi_service_repo)
        copy_versioned_dot_env_to_root(history_env_version, bucket_name, svc_name)
    elif rebuild_env_file and not git_env_version:
        logger.info_yellow("no env file git version provided and rebuild flag provided, will rebuild current development .env version, upload it directly to the root of the env bucket")
        create_and_upload_dot_env_for_dev_version(env_name, svc_name, is_multi_service_repo, env_files_path=env_files_path)
        dev_version = get_dev_version(env_name, VERSION_SUFFIX)
        git_env_version = update_env_history_for_dev_version(env_name, svc_name, dev_version, is_multi_service_repo, version_history_folder)
        if env_name == STAGING:
            svc_prod_envs = get_svc_prod_env_names(svc_name, is_multi_service_repo)
            logger.info(f"Hotfix: updating version history for prod envs only for currently deployed service: {svc_prod_envs}")
            for env in svc_prod_envs:
                update_env_history_for_dev_version(env, svc_name, dev_version, is_multi_service_repo, version_history_folder)

    if not history_env_version:
        logger.info(f"env_version is undefined setting it to dev_version {dev_version}")
        history_env_version = dev_version

    logger.info_green(f"finished updating env vars file for {svc_name} in {env_name}")
    set_current_env_vars_version(env_name=env_name,
                                 env_file_version=git_env_version,
                                 env_version=history_env_version,
                                 svc_name=svc_name,
                                 is_multi_service_repo=is_multi_service_repo,
                                 version_history_folder=version_history_folder)
    return git_env_version, dev_version


def write_env_vars_for_lambda(git_env_version: str):
    logger.info("writing env vars required for lambda")
    version_to_deploy = os.getenv('VERSION_TO_DEPLOY') # on repository_dispatch
    node_version = os.getenv('NODE_VERSION')
    if version_to_deploy:
        write_github_env(version_to_deploy, 'DEPLOYED_ARTIFACT_VERSION')
    if git_env_version:
        write_github_env(git_env_version, 'DEPLOYED_ENV_FILE_VERSION')
    if not node_version:
        write_github_env(DEFAULT_NODE_VERSION, 'NODE_VERSION')

def set_deployed_env_file_version_for_lambda(git_env_version: str, dev_version: str):
    logger.info("overriding DEPLOYED_ENV_FILE_VERSION (required for lambda)")
    deployed_env_file_version = None
    if git_env_version:
        deployed_env_file_version = git_env_version
    if dev_version:
        deployed_env_file_version = dev_version
    if deployed_env_file_version:
        write_github_env(deployed_env_file_version, 'DEPLOYED_ENV_FILE_VERSION')




def main():
    try:
        env_name = get_required_env_var("ENV_NAME")
        svc_type = get_required_env_var("SVC_TYPE")
        svc_name = get_required_env_var("SVC_NAME")

        git_env_version = os.getenv("ENV_FILE_VERSION")  # can be in format: v$semver-ENV (e.g. v1.0.0-ENV)
        rebuild_env_file = os.getenv("REBUILD_ENV_FILE", "false") == "true"
        is_multi_service_repo = get_multi_service_repo(svc_type)

        # TODO: check if yarkon pipeline also needs this
        if svc_type == 'lambda':
            write_env_vars_for_lambda(git_env_version)

        if not rebuild_env_file and not git_env_version:
            logger.info_cyan("no env file version provided, and no rebuild flag provided, skipping")
            return


        git_env_version, dev_version = handle_dot_env_and_history_update(env_name, svc_name, git_env_version, rebuild_env_file, is_multi_service_repo)

        logger.info_green("finished updating env vars files")

        if env_name in STG_PROD_ENVS and dev_version:
            logger.info_yellow(f"env is {env_name}, hence this is a hotfix build and we need to tag the repo with the env vars dev version for service upon deployment success")
            write_github_env(dev_version, "ENV_FILE_DEV_VERSION")

        # TODO: check if yarkon pipeline also needs this
        if svc_type == 'lambda':
            set_deployed_env_file_version_for_lambda(git_env_version, dev_version)

    except Exception as e:
        logger.trace_back(e.__traceback__)
        exit_on_error_and_write_summary(f"couldn't update env vars files due to error: {e}")


if __name__ == '__main__':
    main()
