import json
import re
import shutil
from base64 import b64decode
from pathlib import Path

from common import (
    convert_tag_to_semver,
    exec_command,
    get_env_variable,
    get_env_variable_required,
    print_message,
    set_env_variable,
)
from src.interface.flutter_project import FlutterProjectInterface


class FlutterApp(FlutterProjectInterface):
    def compile(self):
        super().compile()

        is_flavored = get_env_variable("SCI_FLAVORED")
        no_tree_shake_icons = get_env_variable("SCI_FLUTTER_NO_TREE_SHAKE_ICONS")

        build_command = self._build_app_base()

        if no_tree_shake_icons:
            build_command += " --no-tree-shake-icons"

        environment = "development"
        if get_env_variable_required("CI_COMMIT_REF_NAME") in ["master", "main"]:
            environment = "homolog"
        if get_env_variable("CI_COMMIT_TAG"):
            environment = "production"

        if is_flavored:
            target_dir = get_env_variable("SCI_FLAVOR_TARGET_DIR")

            target = f"{target_dir if target_dir else 'lib'}/main_{environment}.dart"

            build_command += f" --flavor={environment} --target={target}"

        build_command += self._dart_define_values(environment)

        self._store_keystore_data()

        self._generate_key_properties()

        self._install_ndk()

        self._exec_flutter_command(build_command)

    def _store_keystore_data(self):
        keystore_content = get_env_variable_required(
            "SCI_ANDROID_KEYSTORE_JKS_FILE_BASE64"
        )

        with open("android/app/upload-keystore.jks", "wb") as keystore_file:
            keystore_file.write(b64decode(keystore_content))

        print_message(
            "Keystore file successfully created. "
            "Please ensure that the keystore file is not included in the repository."
        )

    def _generate_key_properties(self):
        key_alias = get_env_variable_required("SCI_ANDROID_KEY_ALIAS")
        key_password = get_env_variable_required("SCI_ANDROID_KEY_PASSWORD")
        store_password = get_env_variable_required("SCI_ANDROID_STORE_PASSWORD")

        with open(
            "android/key.properties", "w", encoding="utf-8"
        ) as key_properties_file:
            key_properties_file.write(
                f"keyAlias={key_alias}\n"
                f"keyPassword={key_password}\n"
                f"storeFile=upload-keystore.jks\n"
                f"storePassword={store_password}\n"
            )

        print_message(
            "Key properties file successfully created. "
            "Please ensure that the key properties file is not included in the repository."
        )

    def _install_ndk(self):
        """Install Android NDK before building."""
        if not shutil.which("sdkmanager"):
            print_message("sdkmanager not found, skipping NDK installation")
            return

        ndk_version = self._extract_ndk_version()
        ndk_package = self._resolve_ndk_package(ndk_version)
        self._execute_ndk_installation(ndk_package)

    def _extract_ndk_version(self):
        """Extract NDK version from project files."""
        ndk_version = self._extract_ndk_version_from_gradle()
        if not ndk_version:
            ndk_version = self._extract_ndk_version_from_properties()
        return ndk_version

    def _extract_ndk_version_from_gradle(self):
        """Extract NDK version from gradle files."""
        gradle_files = ["android/app/build.gradle.kts", "android/app/build.gradle"]

        for gradle_file in gradle_files:
            if not Path(gradle_file).is_file():
                continue

            try:
                with open(gradle_file, "r", encoding="utf-8") as f:
                    content = f.read()
                    match = re.search(r'ndkVersion\s*=?\s*"([^"]+)"', content)
                    if match:
                        return match.group(1)
            except Exception:
                continue

        return None

    def _extract_ndk_version_from_properties(self):
        """Extract NDK version from gradle.properties."""
        properties_file = "android/gradle.properties"
        if not Path(properties_file).is_file():
            return None

        try:
            with open(properties_file, "r", encoding="utf-8") as f:
                content = f.read()
                match = re.search(r"android\.ndkVersion\s*=\s*([^\s]+)", content)
                if match:
                    return match.group(1)
        except Exception:
            pass

        return None

    def _resolve_ndk_package(self, ndk_version):
        """Resolve NDK package name from version or get latest."""
        if ndk_version:
            print_message(f"Project NDK version: {ndk_version}")
            return f"ndk;{ndk_version}"

        return self._get_latest_ndk_package()

    def _get_latest_ndk_package(self):
        """Get the latest available NDK package."""
        try:
            cmd = (
                "sdkmanager --list 2>/dev/null | grep 'ndk;' | "
                "grep -v -E 'ndk-bundle|-rc' | tail -1 | awk '{print $1}'"
            )
            result = exec_command(
                cmd,
                error_message="Failed to get latest NDK version",
            )
            ndk_package = result.output.strip() if result and result.output else None
        except Exception:
            ndk_package = None

        if ndk_package:
            print_message(f"No NDK version specified, using latest: {ndk_package}")
        else:
            print_message("Could not determine NDK version")

        return ndk_package

    def _execute_ndk_installation(self, ndk_package):
        """Execute the NDK installation command."""
        if not ndk_package:
            print_message("No NDK package to install")
            return

        install_cmd = f"yes | sdkmanager --install '{ndk_package}' || true"

        exec_command(install_cmd, error_message="Failed to install NDK")
        print_message("=== Android NDK installed ===")

    def _dart_define_values(self, environment):
        sci_dart_define_config = get_env_variable("SCI_DART_DEFINE_CONFIG")

        dart_define_values = ""

        if sci_dart_define_config:
            sci_dart_define_config = json.loads(sci_dart_define_config)

            if "common" in sci_dart_define_config:
                for key, value in sci_dart_define_config["common"].items():
                    dart_define_values += f" --dart-define={key}={value}"

            if environment in sci_dart_define_config:
                for key, value in sci_dart_define_config[environment].items():
                    dart_define_values += f" --dart-define={key}={value}"

        return dart_define_values

    def package(self):
        """Esse método, apesar de obrigatório na estrutura, não é usado por Aplicativos Flutter."""

    def deploy(self):
        is_flavored = get_env_variable("SCI_FLAVORED")
        environment = "development"
        file_name = f"app-{self.build_kind}"
        use_appstore = False

        if is_flavored:
            if get_env_variable_required("CI_COMMIT_REF_NAME") in ["master", "main"]:
                environment = "homolog"
            elif get_env_variable("CI_COMMIT_TAG"):
                environment = "production"
                use_appstore = True

            file_name = f"app-{environment}-{self.build_kind}"

        if use_appstore:
            self._send_to_appstore(file_name)
        else:
            self._send_to_firebase(environment, file_name)

    def _send_to_appstore(self, file_name):
        semver_version = convert_tag_to_semver(
            get_env_variable_required("CI_COMMIT_TAG")
        )
        set_env_variable("SEMVER_VERSION", semver_version)
        set_env_variable(
            "AAB_FILE_PATH",
            f"{get_env_variable_required('CI_PROJECT_DIR')}/build/app/outputs/bundle/productionRelease/{file_name}.aab",
        )
        decoded_bytes = b64decode(get_env_variable_required("SCI_PLAY_STORE_JSON_KEY"))

        with open("play-store-key.json", "wb") as playstore_file:
            playstore_file.write(decoded_bytes)

        shutil.copytree(
            "/root/.config/fastlane",
            f"{get_env_variable_required('CI_PROJECT_DIR')}/fastlane",
        )

        exec_command("fastlane deploy", error_message="Execução do Fastlane falhou.")
