import json
import os
import shutil

from typing import Union
from github.env import get_required_env_var, exit_on_error_and_write_summary
from actions_logging.app_logging import logger
from common.common import run_command
from nexus.nexus_api import get_package_versions
from packaging.version import Version

REPO = get_required_env_var("GITHUB_REPOSITORY") #'saferxlib'
DEFAULT_TS_CONFIG_PATH = './tsconfig.json'
LOWEST_VERSION = '0.0.0'
DEFAULT_DISTRIBUTION_PATH = './dist'

def get_distribution_path() -> str:
    """
        Check and set the distribution folder
        If path not exists - Fail the process
    """
    ts_dist_path = DEFAULT_DISTRIBUTION_PATH
    if os.path.isfile(DEFAULT_TS_CONFIG_PATH):
        try:
            with open(DEFAULT_TS_CONFIG_PATH) as ts_config_file:
                tsconfig = json.load(ts_config_file)
            ts_out_dir_path = tsconfig['compilerOptions']['outDir']
            if ts_out_dir_path:
                ts_dist_path = ts_out_dir_path
        except KeyError as ke:
            logger.error(f'get_distribution_path -> Error getting tsconfig json property: {ke}')
        except Exception as e:
            logger.error(f'get_distribution_path -> Error fetching outDir from tsconfig file: {e}')
    if not os.path.exists(ts_dist_path):
        exit_on_error_and_write_summary(f'The build distribution path {ts_dist_path} does not exist.')
    return ts_dist_path

def copy_file_to_dist(filename, dist_path) -> None:
    try:
        shutil.copyfile(f'./{filename}', f'./{dist_path}/{filename}')
    except Exception as e:
        exit_on_error_and_write_summary(f'Failed to copy {filename} file to {dist_path} due to: {e}')

def get_latest_nexus_version() -> str:
    """
        Fetch the lib latest
        version from Nexus.
    """
    try:
        items = get_package_versions(REPO)
        if len(items) < 1:
            return LOWEST_VERSION
        for item in items:
            npm_version = item.get('npm', {}).get('version', None)
            if npm_version:
                return npm_version
        json_formatted_str = json.dumps(items, indent=2)
        exit_on_error_and_write_summary(f'Something went wrong\nFailed to find nexus versions, items array: \n {json_formatted_str}')
    except Exception as e:
        exit_on_error_and_write_summary(f'get_latest_nexus_version failed due to: {e}')

def check_lib_version(dist_path):
    """
        Validate if lib version is latest
        from package.json
        If not - exit process
    """
    package_json_path = f'{dist_path}/package.json'
    try:
        with open(package_json_path) as package_json_file:
            package_json_content = json.load(package_json_file)
        current_version = package_json_content.get('version')
        nexus_latest_version = get_latest_nexus_version()
        if Version(current_version) <= Version(nexus_latest_version):
            exit_on_error_and_write_summary(f'get_check_lib_version -> The version {current_version} is lower/equal from latest.')
        logger.info_green(f'Nexus latest version {nexus_latest_version}.')
        logger.info_green(f'Library deployed version: {current_version}')
    except FileNotFoundError as e:
        exit_on_error_and_write_summary(
            f'Cannot determind the desired version.\n \
            The package json file {package_json_path} is not exists.'
        )
    except Exception as e:
        exit_on_error_and_write_summary(f'get_check_lib_version -> Error fetching version from package json file: {e}')
        
def publish_library(dist_path) -> None:
    """
        Publish the lib to local npm (based on .npmrc)
    """
    try:
        logger.info_green('Trying to publish...')
        os.chdir(dist_path)
        logger.info_green(f'Current folder: {os.getcwd()}.')
        run_command("npm publish", print_output=True, return_output=False, exit_on_error=True)
        logger.info_green('Publish was successful')
    except Exception as e:
        exit_on_error_and_write_summary(f"Error running publish_library: {e}")

def main() -> None:
    """
        Deploy the created dist folder to nexus
    """
    logger.info_green(f'Library name: {REPO}')
    dist_path = get_distribution_path()
    logger.info_green(f'Distribution path: {dist_path}')
    copy_file_to_dist('.npmrc', dist_path)
    copy_file_to_dist('package.json', dist_path)
    check_lib_version(dist_path)
    root = os.getcwd()
    publish_library(dist_path)
    os.chdir(root)
    logger.info_green('Done.')

if __name__ == '__main__':
    main()
