"""
Shopify OAuth2 backend, docs at:
    https://python-social-auth.readthedocs.io/en/latest/backends/shopify.html
"""

import shopify

from ..exceptions import AuthCanceled, AuthFailed
from ..utils import handle_http_errors
from .oauth import BaseOAuth2


class ShopifyOAuth2(BaseOAuth2):
    """Shopify OAuth2 authentication backend"""

    name = "shopify"
    ID_KEY = "shop"
    EXTRA_DATA = [("shop", "shop"), ("website", "website"), ("expires", "expires")]
    REDIRECT_STATE = False

    @property
    def shopify_api_version(self):
        return self.setting("API_VERSION", "2020-10")

    def get_user_details(self, response):
        """Use the shopify store name as the username"""
        return {"username": str(response.get("shop", "")).replace(".myshopify.com", "")}

    def extra_data(self, user, uid, response, details=None, *args, **kwargs):
        """Return access_token and extra defined names to store in
        extra_data field"""
        data = super().extra_data(user, uid, response, details, *args, **kwargs)
        session = shopify.Session(
            self.data.get("shop").strip(), version=self.shopify_api_version
        )
        # Get, and store the permanent token
        token = session.request_token(data["access_token"])
        data["access_token"] = token
        return dict(data)

    def auth_url(self):
        key, secret = self.get_key_and_secret()
        shopify.Session.setup(api_key=key, secret=secret)
        scope = self.get_scope()
        state = self.state_token()
        self.strategy.session_set(self.name + "_state", state)
        redirect_uri = self.get_redirect_uri(state)
        session = shopify.Session(
            self.data.get("shop").strip(), version=self.shopify_api_version
        )
        return session.create_permission_url(scope=scope, redirect_uri=redirect_uri)

    @handle_http_errors
    def auth_complete(self, *args, **kwargs):
        """Completes login process, must return user instance"""
        self.process_error(self.data)
        access_token = None
        key, secret = self.get_key_and_secret()
        try:
            shop_url = self.data.get("shop")
            shopify.Session.setup(api_key=key, secret=secret)
            shopify_session = shopify.Session(
                shop_url, version=self.shopify_api_version, token=self.data
            )
            access_token = shopify_session.token
        except shopify.ValidationException:
            raise AuthCanceled(self)
        else:
            if not access_token:
                raise AuthFailed(self, "Authentication Failed")
        return self.do_auth(
            access_token, shop_url, shopify_session.url, *args, **kwargs
        )

    def do_auth(self, access_token, shop_url, website, *args, **kwargs):
        kwargs.update(
            {
                "backend": self,
                "response": {
                    "shop": shop_url,
                    "website": f"http://{website}",
                    "access_token": access_token,
                },
            }
        )
        return self.strategy.authenticate(*args, **kwargs)
