


import hashlib
import hmac
from datetime import datetime
from urllib.parse import parse_qsl, urlencode

import pytz
import requests
from flask import Request, redirect
from requests_oauthlib import OAuth2Session

from configs.firebase import db
from functions.Shopify.Auth import apiVersion
from V2.functions.Applications.main import Application
from V2.functions.Etsy.Shops import getEtsyShop
from V2.functions.Shops.Auth import (ENTERPRISES, EXCLUDE_ENTERPRISES, PLANS,
                                     getAuthState)
from V2.functions.Shops.main import Shop
from V2.functions.Users.main import Enterprise, User, getUser
from V2.middlewares.auth import API_Error


def token(request:Request):
    state = request.args.get("state")
    authState = getAuthState(state)
    if not authState: return "Invalid state.", 404
    code = request.args.get("code")
    success = False
    shopId = None
    uid, enterpriseId, platformId = authState.get("uid"), authState.get("enterpriseId"), authState.get("platformId")
    enterprise = Enterprise.get(enterpriseId)
    planId = enterprise.planId
    app = Application.get(platformId+(
        "zNAlxdaZG6hKf6vexv6ljqHyP8i1" if (planId in PLANS or enterpriseId in ENTERPRISES and enterpriseId not in EXCLUDE_ENTERPRISES) else enterpriseId
        )
    )
    if platformId == "1":
        shopId = etsyToken(
            uid=uid,
            enterpriseId=enterpriseId,
            redirect_uri=authState.get("redirectUrl"),
            code_verifier=authState.get("code_verifier"),
            code=code,
            app=app
        )
        if shopId: success = True
    if platformId == "2":
        shopId = shopifyToken(
            uid=uid,
            enterpriseId=enterpriseId,
            app=app,
            query_string = request.query_string,
            **request.args.to_dict()
        )
        if shopId: success = True
    if platformId == "3":
        shopId = wooToken(
            user_id=uid,
            enterpriseId=enterpriseId,
            state=state,
            **request.args.to_dict()
        )
    return redirect(f"https://{authState.get('domain')}/shops?shop={shopId}&success={success}&state={state}")
    
def shopifyToken(uid, enterpriseId, app: Application,query_string, **params):
    query_str = query_string.decode("utf-8")

    # Parse into list of (key, value) pairs
    parsed = parse_qsl(query_str, keep_blank_values=True)

    # Filter out the hmac from the params
    filtered_params = [(k, v) for k, v in parsed if k != "hmac"]

    # Sort and rebuild the query string exactly as Shopify expects
    sorted_query = urlencode(sorted(filtered_params))

    # Calculate HMAC
    calculated_hmac = hmac.new(
        app.apiSecret.encode("utf-8"),
        sorted_query.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()

    expected_hmac = params.get("hmac")

    # Compare
    if not hmac.compare_digest(calculated_hmac, expected_hmac):
        print("[WARNING] Skipping HMAC verification (debug only!)")
    # return None  # or allow it to continue if you're debugging


    # Step 2: Exchange authorization code for access token
    url = f"https://{params.get('shop')}"
    token_url = f"{url}/admin/oauth/access_token"
    payload = {
        "client_id": app.apiKey,
        "client_secret": app.apiSecret,
        "code": params.get("code"),
    }

    print(url, payload)

    response = requests.post(token_url, json=payload)
    if response.status_code != 200:
        raise ValueError("Failed to exchange token: " + response.text)

    access_token = response.json().get("access_token")

    # Step 3: Fetch shop details
    headers = {"X-Shopify-Access-Token": access_token}
    shop_base = f"{url}/admin/api/{apiVersion}/shop.json"
    res = requests.get(shop_base, headers=headers)
    if res.status_code != 200:
        raise ValueError("Failed to fetch shop details: " + res.text)

    shop_data = res.json().get('shop')
    shop_obj = Shop(
        uid=uid,
        platformId=app.platformId,
        enterpriseId=enterpriseId,
        platformShopId=str(shop_data.get("id")),
        platformName=app.platformName,
        appId=app.id,
        name=shop_data.get('name'),
        url=url,
        accessToken=access_token
    )
    return shop_obj.save().id


def etsyToken(uid,enterpriseId, redirect_uri, code, code_verifier, app: Application) -> Shop:
    if app:
        oauth = OAuth2Session(
            app.apiKey,
            redirect_uri = redirect_uri
        )
        token = oauth.fetch_token("https://api.etsy.com/v3/public/oauth/token", 
            code=code,
            code_verifier=code_verifier,
            include_client_id=True,
            headers={
             "x-api-key": app.apiKey,
            }
        )
        
        if not token: raise API_Error("Cannot get token.")
        oauth.token = token
        etsyShop = getEtsyShop(oauth)
        shop = Shop(
            name=etsyShop.get("shop_name"),
            platformShopId=etsyShop.get("shop_id"),
            platformId=app.platformId,
            platformName=app.platformName,
            appId=app.id,
            uid=uid,
            enterpriseId=enterpriseId,
            url=etsyShop.get("url"),
            accessToken=token.get('access_token'),
            refreshToken=token.get('refresh_token'),
            apiVersion="v3",
            tokenType=token.get("token_type"),
            expiresAt=int(datetime.now(pytz.utc).timestamp()+token.get("expires_in")),
        ).save()
        return shop.id
    raise API_Error("App not found.")



def wooToken(**data):
    uid = data.get("uid")
    enterpriseId=enterpriseId,
    consumerKey = data.get("consumer_key")
    consumerSecret = data.get("consumer_secret")
    state = data.get("state")
    ref = db.collection('shopsCredentials').where('uid', '==', uid).where('platformId', '==', "3").where('state', "==", state).get() 
    for doc in ref:
        doc.reference.update(dict(
            consumerKey=consumerKey,
            consumerSecret=consumerSecret
        ))
        return doc.id