from typing import Any, Optional

from sentry import options
from sentry.auth.partnership_config import SPONSOR_OAUTH_NAME, ChannelName
from sentry.auth.provider import MigratingIdentityId
from sentry.auth.providers.oauth2 import OAuth2Callback, OAuth2Provider

from .constants import ACCESS_TOKEN_URL, AUTHORIZE_URL
from .views import FetchUser, FlyConfigureView, FlyOAuth2Login


class FlyOAuth2Provider(OAuth2Provider):
    name = SPONSOR_OAUTH_NAME[ChannelName.FLY_IO]
    is_partner = True
    access_token_url = ACCESS_TOKEN_URL
    authorize_url = AUTHORIZE_URL

    def __init__(self, org=None, **config):
        self.org = org
        super().__init__(**config)

    def get_client_id(self):
        return options.get("auth-fly.client-id")

    def get_client_secret(self):
        return options.get("auth-fly.client-secret")

    def get_configure_view(self):
        # Utilized from organization_auth_settings.py when configuring the app
        # Injected into the configuration form
        return FlyConfigureView.as_view()

    def get_auth_pipeline(self):
        return [
            FlyOAuth2Login(client_id=self.get_client_id()),
            OAuth2Callback(
                access_token_url=ACCESS_TOKEN_URL,
                client_id=self.get_client_id(),
                client_secret=self.get_client_secret(),
            ),
            FetchUser(org=self.org),
        ]

    def get_refresh_token_url(self):
        return ACCESS_TOKEN_URL

    @classmethod
    def build_config(self, state: Any, organization: Optional[Any] = None):
        """
        On configuration, we determine which provider organization to configure SSO for.
        This configuration is then stored and passed into the pipeline instances during SSO
        to determine whether the Auth'd user has the appropriate access to the provider org

        {
            'state': '9da4041848844e8088864eaea3c3a705',
            'data': {
                'access_token': 'fo1_6xgeCrB8ew8vFQ86vdaakBSFTVDGCzOUvebUbvgPGhI',
                'token_type': 'Bearer',
                'expires_in': 7200,
                'refresh_token': 'PmUkAB75UPLKGZplERMq8WwOHnsTllZ5HveY4RvNUTk',
                'scope': 'read',
                'created_at': 1686786353},
                'user': {
                    'resource_owner_id': 'k9d01lp82rky6vo2',
                    'scope': ['read'],
                    'expires_in': 7200,
                    'application': {'uid': 'elMJpuhA5bXbR59ZaKdXrxXGFVKTypGHuJ4h6Rfw1Qk'},
                    'created_at': 1686786353,
                    'user_id': 'k9d01lp82rky6vo2',
                    'user_name': 'Nathan',
                    'email': 'k9d01lp82rky6vo2@customer.fly.io',
                    'organizations': [
                        {'id': 'nathans-org', 'role': 'member'},
                        {'id': '0vogzmzoj1k5xp29', 'role': 'admin'}
                    ]
                }
            }
        }
        """
        org = organization
        if not organization:
            data = state["data"]
            # TODO: determine which org to configure SSO for
            org = data["user"]["organizations"][0]

        return {"org": org}

    def build_identity(self, state):
        """
        ex Response:
        {
            'resource_owner_id': 'k9d01lp82rky6vo2',
            'scope': ['read'],
            'expires_in': 7200,
            'application': {
                'uid': 'elMJpuhA5bXbR59ZaKdXrxXGFVKTypGHuJ4h6Rfw1Qk'
            },
            'created_at': 1686785304,
            'user_id': 'k9d01lp82rky6vo2',
            'user_name': 'Nathan',
            'email': 'k9d01lp82rky6vo2@customer.fly.io',
            'organizations': [
                {'id': 'g1lx9my4pzemqwk7', 'role': 'admin'},
                {'id': '0vogzmzoj1k5xp29', 'role': 'admin'}
            ]
        }
        """
        data = state["data"]
        user_data = state["user"]

        # XXX(epurkhiser): We initially were using the email as the id key.
        # This caused account dupes on domain changes. Migrate to the
        # account-unique sub key.
        user_id = MigratingIdentityId(id=user_data["user_id"], legacy_id=user_data["email"])

        return {
            "id": user_id,
            "email": user_data["email"],
            "name": user_data["email"],
            "data": self.get_oauth_data(data),
            "email_verified": False,
        }
