import json
import mimetypes
import os
import tarfile
from pathlib import Path

import boto3

from common import (
    exit_message,
    get_env_variable,
    get_env_variable_required,
    is_semver,
    print_message,
)
from common.seniorx_helper import SeniorXHelper
from src.interface.angular_project import AngularProjectInterface


class AngularSeniorX(AngularProjectInterface):
    def _build(self):
        if self.sci_deploy_cdn:
            self._build_to_cdn()
        else:
            self._execute_npm_command("build --production")

    def package(self):
        sci_frontend_updater_bucket_name = get_env_variable_required(
            "SCI_FRONTEND_UPDATER_BUCKET_NAME"
        )
        sci_frontend_updater_role_arn = get_env_variable(
            "SCI_FRONTEND_UPDATER_ROLE_ARN"
        )

        app_name, domain, service, service_dependencies = (
            self._get_application_details()
        )

        with open("dist/frontend-info.json", "w", encoding="utf-8") as frontend_info:
            json.dump(
                {
                    "version": self.version,
                    "app": app_name,
                    "domain": domain,
                    "service": service,
                    "serviceDependencies": service_dependencies,
                },
                frontend_info,
                indent=2,
            )

        self.compress_frontend()

        if get_env_variable("AWS_ACCESS_KEY_ID"):
            del os.environ["AWS_ACCESS_KEY_ID"]
        if get_env_variable("AWS_SECRET_ACCESS_KEY"):
            del os.environ["AWS_SECRET_ACCESS_KEY"]

        sts_client = boto3.client("sts")
        assumed_role = sts_client.assume_role(
            RoleArn=sci_frontend_updater_role_arn, RoleSessionName="FrontendUpdater"
        )
        credentials = assumed_role["Credentials"]

        s3_client = boto3.client(
            "s3",
            aws_access_key_id=credentials["AccessKeyId"],
            aws_secret_access_key=credentials["SecretAccessKey"],
            aws_session_token=credentials["SessionToken"],
        )

        print_message("Enviando frontend compactado para o S3: senior-frontend")

        s3_client.upload_file(
            f"{self.ci_project_name}.tar.gz",
            "senior-frontend",
            f"{self.ci_project_name}/{self.version}/{self.ci_project_name}.tar.gz",
        )

        print_message(f"Enviando dist para o S3: {sci_frontend_updater_bucket_name}")

        app_detail_path = f"{app_name}/{domain}/{service}/{self.version}"

        extra_args = {}

        tags = {
            "TagSet": [
                {"Key": "Type", "Value": "snapshot-temp"},
            ]
        }

        for path in Path("dist").rglob("*"):
            if path.is_file():
                mimetype, _ = mimetypes.guess_type(path)

                if mimetype:
                    extra_args["ContentType"] = mimetype

                key = f"{app_detail_path}/{str(path.relative_to('dist'))}"

                s3_client.upload_file(
                    str(path),
                    sci_frontend_updater_bucket_name,
                    key,
                    ExtraArgs=extra_args,
                )

                is_version_snapshot = not is_semver(self.version)

                if is_version_snapshot:
                    s3_client.put_object_tagging(
                        Bucket=sci_frontend_updater_bucket_name, Key=key, Tagging=tags
                    )

        if self.sci_deploy_cdn:
            self._package_to_cdn()

        print_message(f"Versão {self.version} empacotada com sucesso!")

    def compress_frontend(self):
        print_message("Compactando frontend")

        frontend_compressed_file_name = "frontend.tar.gz"

        with tarfile.open(frontend_compressed_file_name, "w:gz") as tar:
            tar.add("dist", arcname=".")

        with tarfile.open(f"{self.ci_project_name}.tar.gz", "w:gz") as tar:
            tar.add("dist", arcname=self.ci_project_name)

        Path(frontend_compressed_file_name).rename(
            Path("dist") / frontend_compressed_file_name
        )

    def deploy(self):
        seniorx_frontend_helper = SeniorXHelper()

        print_message(
            f"Realizando deploy da versão {self.version} no ambiente {seniorx_frontend_helper.environment_host}"
        )

        app_name, domain, service, _ = self._get_application_details()

        deploy_info = seniorx_frontend_helper.get_deploy_info(app_name, domain, service)

        if not deploy_info:
            print_message(
                "Frontend não encontrado na plataforma. Tentando realizar implantação..."
            )

            menu_module_id = get_env_variable("MENU_MODULE_ID")

            if not menu_module_id:
                exit_message(
                    "Id do módulo de menu não definido. Não será possível implantar o frontend. "
                    "Para implantar é preciso seguir a seguinte wiki: "
                    "https://wiki.senior.com.br/pt-br/DevSecOps/Fluxos-CI-CD/Deploy#implanta%C3%A7%C3%A3o-de-frontend"
                )

            menu_module_name = seniorx_frontend_helper.get_menu_module_name(
                menu_module_id
            )

            if not menu_module_name:
                exit_message(
                    f"Módulo com o id {menu_module_id} não encontrado. Não será possível implantar o frontend. "
                    "Para implantar é preciso seguir a seguinte wiki: "
                    "https://wiki.senior.com.br/pt-br/DevSecOps/Fluxos-CI-CD/Deploy#implanta%C3%A7%C3%A3o-de-frontend"
                )

            deploy_alias = f"{app_name}/{domain}/{service}"

            seniorx_frontend_helper.insert_deploy(
                deploy_alias, self.version, menu_module_id
            )

            print_message("Frontend implantado com sucesso!")
        else:
            deploy_id = deploy_info["deployId"]

            print_message("Atualizando deploy na SeniorX")

            seniorx_frontend_helper.update_deploy(deploy_id, self.version)

    def _build_to_cdn(self):
        sci_cdn_url = get_env_variable_required("SCI_CDN_URL")

        app_name, domain, service, _ = self._get_application_details()

        app_detail_path = f"{app_name}/{domain}/{service}/{self.version}/"

        self._execute_npm_command(
            f"build --production -- --deploy-url {sci_cdn_url}/{app_detail_path}"
        )
