from __future__ import annotations

from allauth.socialaccount.providers.base import ProviderAccount
from allauth.socialaccount.providers.dataporten.views import DataportenOAuth2Adapter
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider


class DataportenAccount(ProviderAccount):
    def get_avatar_url(self):
        """
        Returns a valid URL to an 128x128 .png photo of the user
        """
        # Documentation for user profile photos can be found here:
        # https://docs.dataporten.no/docs/oauth-authentication/
        photo = self.account.extra_data["profilephoto"]
        return f"https://api.dataporten.no/userinfo/v1/user/media/{photo}"


class DataportenProvider(OAuth2Provider):
    id = "dataporten"
    name = "Dataporten"
    account_class = DataportenAccount
    oauth2_adapter_class = DataportenOAuth2Adapter

    def extract_uid(self, data):
        """
        Returns the primary user identifier, an UUID string
        See: https://docs.dataporten.no/docs/userid/
        """
        return data["userid"]

    def extract_extra_data(self, data):
        """
        Extracts fields from `data` that will be stored in
        `SocialAccount`'s `extra_data` JSONField.

        All the necessary data extraction has already been done in the
        complete_login()-view, so we can just return the data.
        PS: This is default behaviour, so we did not really need to define
            this function, but it is included for documentation purposes.

        Typical return dict:
        {
            "userid": "76a7a061-3c55-430d-8ee0-6f82ec42501f",
            "userid_sec": ["feide:andreas@uninett.no"],
            "name": "Andreas \u00c5kre Solberg",
            "email": "andreas.solberg@uninett.no",
            "profilephoto": "p:a3019954-902f-45a3-b4ee-bca7b48ab507",
        }
        """
        return data

    def extract_common_fields(self, data):
        """
        This function extracts information from the /userinfo endpoint which
        will be consumed by allauth.socialaccount.adapter.populate_user().
        Look there to find which key-value pairs that should be saved in the
        returned dict.

        Typical return dict:
        {
            "userid": "76a7a061-3c55-430d-8ee0-6f82ec42501f",
            "userid_sec": ["feide:andreas@uninett.no"],
            "name": "Andreas \u00c5kre Solberg",
            "email": "andreas.solberg@uninett.no",
            "profilephoto": "p:a3019954-902f-45a3-b4ee-bca7b48ab507",
            "username": "andreas",
        }
        """
        # Make shallow copy to prevent possible mutability issues
        data = dict(data)

        # If a Feide username is available, use it. If not, use the "username"
        # of the email-address
        for userid in data.get("userid_sec"):
            usertype, username = userid.split(":")
            if usertype == "feide":
                data["username"] = username.split("@")[0]
                break
        else:
            # Only entered if break is not executed above
            data["username"] = data.get("email").split("@")[0]

        return data


provider_classes = [DataportenProvider]
