import json
from dataclasses import dataclass, field
from pathlib import Path

# PyQGIS
from qgis.core import Qgis
from qgis.PyQt.QtCore import QUrl

# plugin
from oslandia.constants import UTM_CONTENT_ISSUEBROWSER
from oslandia.toolbelt import PlgLogger, PlgOptionsManager
from oslandia.toolbelt.network_manager import NetworkRequestsManager


@dataclass
class Group:
    id: int
    full_path: str
    name: str
    avatar_url: str | None = None
    # defined during post init
    api_url: str = field(init=False)
    avatar_local_filepath: Path = field(init=False)

    def __post_init__(self):
        """Post init method to define some of properties of the class."""
        plg_settings = PlgOptionsManager.get_plg_settings()
        local_avatars_cache_folder: Path = plg_settings.local_app_folder.joinpath(
            "avatars"
        )
        self.avatar_local_filepath = local_avatars_cache_folder.joinpath(
            f"grp_{self.id}.png"
        )
        self.api_url = f"{plg_settings.gitlab_api_url_base}groups/{self.id}/"


class GroupRequestManager:
    MAX_LIMIT = 50

    def get_base_url(self) -> str:
        """
        Get base url for group

        Returns: url for group info

        """
        return f"{self.plg_settings.gitlab_api_url_base}groups"

    def __init__(self):
        """
        Helper for stored_data request

        """
        self.log = PlgLogger().log
        self.ntwk_requester_blk = NetworkRequestsManager()
        self.plg_settings = PlgOptionsManager.get_plg_settings()

    def get_group_from_name(
        self, name: str, full_path: str | None = None, group_id: str | None = None
    ) -> Group | None:
        """
        Get a group from name, None if not found

        Args:
            name(str) : group name
            full_path: group full path to search for. Defaults to None.
            group_id: group id to search for. Defaults to None.

        Returns:
            found Group, None if not found
        """
        groups = self.get_group_list(search=name)

        # filters
        if full_path:
            groups = [g for g in groups if g.full_path == full_path]
        if group_id:
            groups = [g for g in groups if g.id == group_id]

        return groups[0] if groups else None

    def get_group_from_id(self, group_id: int) -> Group | None:
        """
        Get a group from name, None if not found

        Args:
            group_id(str) : group id

        Returns:
            found Group, None if not found
        """
        url = f"{self.get_base_url()}/{group_id}"
        # send request
        req_reply = self.ntwk_requester_blk.get_url(
            QUrl(url),
            self.plg_settings.authentification_config_id,
            caller=UTM_CONTENT_ISSUEBROWSER,
        )

        if req_reply:
            data = json.loads(req_reply.data().decode("utf-8"))
            return Group(
                id=data["id"],
                full_path=data["full_path"],
                name=data["name"],
                avatar_url=data["avatar_url"],
            )

    def get_group_list(self, search: str = "") -> list[Group]:
        """
        Get list of group

        Args:
            search: (str): search param (defaut "")

        Returns: list of available group
        """
        self.log(f"{__name__}.get_group_list()")

        i = 1
        result = []
        result_page = self._get_group_list(search=search, page=i, limit=self.MAX_LIMIT)
        while len(result_page) != 0:
            result += result_page
            i = i + 1
            result_page = self._get_group_list(
                search=search, page=i, limit=self.MAX_LIMIT
            )
        return result

    def _get_group_list(
        self, search: str = "", page: int = 1, limit: int = MAX_LIMIT
    ) -> list[Group]:
        """
        Get list of group

        Args:
            search: (str): search param (defaut "")
            page: (int) page number (start at 1)
            limit: (int)

        Returns: list of available project
        """
        url = f"{self.get_base_url()}?page={page}&per_page={limit}"
        if search != "":
            url += f"&search={search}"

        # send request
        req_reply = self.ntwk_requester_blk.get_url(
            QUrl(url),
            self.plg_settings.authentification_config_id,
            caller=UTM_CONTENT_ISSUEBROWSER,
        )
        if req_reply:
            data = json.loads(req_reply.data().decode("utf-8"))

            return [
                Group(
                    id=p_data["id"],
                    full_path=p_data["full_path"],
                    name=p_data["name"],
                    avatar_url=p_data["avatar_url"],
                )
                for p_data in data
            ]
        return []

    def download_avatar(self, group: Group) -> Path | None:
        """Download a group's avatar if it does not exist in the local cache folder.
        File is stored in local cache.

        :param group: group to download avatar for
        :type group: Group

        :return: local path to the downloaded avatar
        :rtype: Optional[Path]
        """
        if not group.avatar_local_filepath.exists() and group.avatar_url is not None:
            self.log(
                f"Downloading avatar for {group.name}",
                log_level=Qgis.MessageLevel.Info,
                push=False,
            )
            self.ntwk_requester_blk.download_file_to(
                remote_url=QUrl(f"{group.api_url}avatar"),
                local_path=group.avatar_local_filepath,
                auth_cfg=self.plg_settings.authentification_config_id,
                caller=UTM_CONTENT_ISSUEBROWSER,
            )
        return group.avatar_local_filepath

    def get_user_access_level(self, group_id: int, user_id: int) -> int | None:
        """Get user access level for a group

        :param group_id: group id
        :type group_id: int
        :param user_id: user id
        :type user_id: int
        :return: access_level as int, None if no reply
        :rtype: Optional[int]
        """
        url = f"{self.get_base_url()}/{group_id}/members/all/{user_id}"
        # send request
        req_reply = self.ntwk_requester_blk.get_url(
            QUrl(url),
            self.plg_settings.authentification_config_id,
            caller=UTM_CONTENT_ISSUEBROWSER,
        )
        if req_reply:
            data = json.loads(req_reply.data().decode("utf-8"))
            return data["access_level"]
