import json
import re
import xml.etree.ElementTree as ET
from os import listdir
from pathlib import Path

from common import get_env_variable, get_env_variable_required, is_semver

POM_XML = "pom.xml"


def get_files_by_extension(file_path, file_extension):
    files = []

    for file in listdir(file_path):
        if file.endswith(file_extension):
            files.append(file)

    return files


def load_properties(filepath: str, sep="=", comment_char="#") -> dict:
    """
    Read the file passed as parameter as a properties file and return as a dict.
    """

    def _get_properties_from_path(path: Path):
        with open(path, "rt", encoding="utf-8") as property_file:
            for line in property_file:
                if line.strip() and not line.strip().startswith(comment_char):
                    key_value = line.strip().split(sep)
                    if len(key_value) > 1:
                        key = key_value[0].strip()
                        value = sep.join(key_value[1:]).strip().strip('"')
                        properties[key] = value

    properties = {}
    path = Path(filepath)
    if path.is_file():
        try:
            _get_properties_from_path(path)
        except UnicodeError as error:
            raise UnicodeError(
                f"The file contains non-Unicode characters, please replace them: {error}"
            ) from error

    return properties


def get_xml_namespace_and_root_element(path: str) -> tuple:
    """
    Read the file passed as parameter as a XML file and return the namespace and the Element.
    """

    tree = ET.parse(path)
    root = tree.getroot()
    namespace = {"mvn": root.tag[1 : root.tag.index("}")]}

    return namespace, root


def get_pom_xml_property(property_name: str) -> str:
    """
    Read pom.xml and return the value of a property.
    """

    namespace, root = get_xml_namespace_and_root_element(POM_XML)

    property_value = root.find(f"mvn:{property_name}", namespace)

    return property_value.text


def load_sdl_properties() -> dict:
    return load_properties("sdl.properties")


def get_svc_name():
    """
    Get name of the service.
    """

    sci_svc_name = get_env_variable("SCI_SVC_NAME")

    if not sci_svc_name:
        generator_app_name_property = "generator.app.name"
        properties = load_sdl_properties()

        if generator_app_name_property in properties:
            sci_svc_name = properties[generator_app_name_property]
        elif Path(POM_XML).is_file():
            sci_svc_name = get_pom_xml_property("artifactId")
        else:
            sci_svc_name = get_env_variable_required("CI_PROJECT_NAME").replace(
                "-backend", ""
            )

    return sci_svc_name


def get_java_version() -> str:
    """
    Get java version of the project, based on SCI_RUNNER_TAG or pom properties
    """
    java_version = get_env_variable_required("SCI_RUNNER_TAG").replace("openjdk", "")
    ci_project_dir = get_env_variable_required("CI_PROJECT_DIR")
    path_to_serach = Path(ci_project_dir)
    pom_files = list(path_to_serach.rglob(POM_XML))

    for pom in pom_files:
        tree = ET.parse(str(pom))
        root = tree.getroot()
        compiler_sources = [
            elem.text.strip()
            for elem in root.iter()
            if "maven.compiler.source" in elem.tag and elem.text
        ]
        for version in compiler_sources:
            if is_semver(version):
                return version
    return java_version


def find_file_by_name(start_dir: Path, filename: str) -> Path | None:
    """
    Procura recursivamente por um arquivo com nome específico.
    Retorna o primeiro arquivo encontrado ou None.
    """
    start_path = Path(start_dir)
    for file in start_path.rglob(filename):
        return file
    return None


def is_file_exist(file_path: str) -> bool:
    return Path(file_path).exists()


def load_strict_json(path: Path):
    with open(path, "r", encoding="utf-8") as f:
        content = f.read()

    content = re.sub(r"//.*", "", content)
    content = re.sub(r"/\*.*?\*/", "", content, flags=re.S)

    return json.loads(content)
