#  standard
import json
from dataclasses import dataclass
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.custom_exceptions import UnavailableUserError
from oslandia.toolbelt import PlgLogger, PlgOptionsManager
from oslandia.toolbelt.network_manager import NetworkRequestsManager


@dataclass
class User:
    id: int
    username: str
    name: str
    avatar_url: str = ""
    avatar_url_gravatar: str | None = None
    email: str = ""

    @property
    def avatar_local_filepath(self) -> Path:
        """Local file path for the downloaded avatar.

        :return: local path to the avatar
        :rtype: Path
        """
        plg_settings = PlgOptionsManager.get_plg_settings()
        local_avatars_cache_folder: Path = plg_settings.local_app_folder.joinpath(
            "avatars"
        )
        return local_avatars_cache_folder.joinpath(f"{self.username}.png")

    @property
    def can_display_archived_project(self) -> bool:
        """Check if user can display archived project

        :return: True if archived project can be displayed, False otherwise
        :rtype: bool
        """
        return self.email.endswith("@oslandia.com")


class UserRequestManager:
    def __init__(self):
        """Helper for user request."""
        self.log = PlgLogger().log
        self.ntwk_requester_blk = NetworkRequestsManager()
        self.plg_settings = PlgOptionsManager.get_plg_settings()

        # avatars management
        self.local_avatars_cache_folder: Path = (
            self.plg_settings.local_app_folder.joinpath("avatars")
        )
        self.local_avatars_cache_folder.mkdir(parents=True, exist_ok=True)

    def get_current_user(self) -> User:
        """Get current connected User.

        Raise UnavailableUserException if we can't get the current User

        Returns: connected User
        """

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

            user = User(
                id=data.get("id"),
                username=data.get("username"),
                email=data.get("email"),
                name=data.get("name"),
                avatar_url=data.get("avatar_url"),
            )

            if not user.avatar_local_filepath.exists():
                self.log(
                    f"Downloading avatar for {user.username}",
                    log_level=Qgis.MessageLevel.Info,
                    push=False,
                )
                self.download_avatar(user)

            return user
        else:
            raise UnavailableUserError("Error while fetching user info")

    def download_avatar(self, user: User) -> Path | None:
        """Download avatar for a user.

        For now, the GitLab API does not allow to download the avatar directly from the
        user endpoint, since it only supports the session cookie.
        See https://gitlab.com/gitlab-org/gitlab/-/issues/441353 to track the upstream
        feature request.

        As fallback, we can use the Gravatar API to download the avatar using the email
        on the /avatar endpoint which returns a JSON like:
        {
            "avatar_url":"https://secure.gravatar.com/avatar/4340[...]?s=64\u0026d=identicon"
        }

        Then we download the avatar from the URL provided in the JSON.

        :param user: user to download avatar for
        :type user: User

        :return: local path to the downloaded avatar
        :rtype: Optional[Path]
        """
        req_reply = self.ntwk_requester_blk.get_url(
            QUrl(
                f"{self.plg_settings.gitlab_api_url_base}avatar?email={user.email}&size=64"
            ),
            self.plg_settings.authentification_config_id,
            caller=UTM_CONTENT_ISSUEBROWSER,
        )
        if req_reply:
            data = json.loads(req_reply.data().decode("utf-8"))
            self.ntwk_requester_blk.download_file_to(
                remote_url=QUrl(data.get("avatar_url")),
                local_path=user.avatar_local_filepath,
                caller=UTM_CONTENT_ISSUEBROWSER,
            )
            return user.avatar_local_filepath
        else:
            return None
