import logging

import requests
from django.apps import apps

from ..utils import get_shop_model, get_auth_shop

logger = logging.getLogger(__name__)

OFFLINE_ACCESS_TOKEN = "urn:shopify:params:oauth:token-type:offline-access-token"
ONLINE_ACCESS_TOKEN = "urn:shopify:params:oauth:token-type:online-access-token"


def exchange_token(shop_domain, session_token, requested_token_type=OFFLINE_ACCESS_TOKEN):
    """Exchange a session token (JWT) for an access token via Shopify's token exchange API."""
    auth_shop = get_auth_shop(shop_domain)

    response = requests.post(
        f"https://{shop_domain}/admin/oauth/access_token",
        data={
            "client_id": auth_shop.shopify_app_api_key,
            "client_secret": auth_shop.shopify_app_api_secret,
            "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
            "subject_token": session_token,
            "subject_token_type": "urn:ietf:params:oauth:token-type:id_token",
            "requested_token_type": requested_token_type,
        },
        headers={
            "Content-Type": "application/x-www-form-urlencoded",
            "Accept": "application/json",
        },
    )

    if response.status_code != 200:
        logger.error(
            "Token exchange failed for %s: %s %s",
            shop_domain, response.status_code, response.text,
        )
        return None

    return response.json()


def ensure_access_token(shop_domain, session_token):
    """Ensure the shop has a valid offline access token, exchanging if needed.

    Returns the shop instance, or None if token exchange failed.
    """
    Shop = get_shop_model()
    shop, created = Shop.objects.get_or_create(shopify_domain=shop_domain)

    if shop.shopify_token:
        return shop

    logger.info("No access token for %s, performing token exchange", shop_domain)

    data = exchange_token(shop_domain, session_token, OFFLINE_ACCESS_TOKEN)
    if not data:
        return None

    shop.shopify_token = data["access_token"]
    shop.access_scopes = data.get("scope", "")[:249]
    shop.save()

    if created:
        shop.installed()

    return shop
