import json
import traceback
from datetime import datetime

import requests

from configs.firebase import SERVER_TIMESTAMP, db
from functions.Enterprises import getItemCost
from functions.LastUpdated import productsLastUpdated, saveProductsLastUpdated
from functions.Products import (convertImage, convertProduct, convertProperty,
                                convertVariant, saveProduct)
from functions.Response import API_Error, saveError
from functions.Shopify.Auth import apiVersion, createHeader
from functions.Shops import getShops
from functions.Suppliers.BlankProducts import worker
from V2.functions.Shopify.main import SHOPIFY_API_VERSION, validate_shopify_id


def execute_graphql(url, headers, query, variables=None):
    """Execute a GraphQL query or mutation."""
    payload = {"query": query, "variables": variables or {}}
    response = requests.post(url, json=payload, headers=headers)
    print(response.text)
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"GraphQL request failed: {response.text}")

def updateAllProducts(params={}):
    """Update all products for active Shopify shops."""
    shops = [shop for shop in getShops(platformId="2", credentials=True) if not shop.get("disabled")]
    res = worker(updateShopProducts, shops)
    return str(res)

def updateShopProducts(shop):
    if shop:
        updates = []
        uid = shop.get('uid')
        shopId = shop.get('id')
        accessToken = shop.get('accessToken')
        url = f"{shop.get('url')}/admin/api/{SHOPIFY_API_VERSION}/graphql.json"
        headers = createHeader(accessToken)
        
        lastUpdate = productsLastUpdated(shopId)
        updated_at_min = datetime.fromtimestamp(lastUpdate.get('timestamp')).isoformat()
        lastOrderTimestamp = lastUpdate.get('timestamp')

        # GraphQL query to fetch products updated after `updated_at_min`
        query = """
        query($updatedAtMin: DateTime, $first: Int!) {
          products(first: $first, query: $updatedAtMin) {
            edges {
              node {
                id
                title
                descriptionHtml
                createdAt
                updatedAt
                tags
                images(first: 10) {
                  edges {
                    node {
                      id
                      originalSrc
                      position
                    }
                  }
                }
                variants(first: 10) {
                  edges {
                    node {
                      id
                      sku
                      inventoryItem {
                        id
                      }
                      price
                      selectedOptions {
                        name
                        value
                      }
                    }
                  }
                }
              }
            }
            pageInfo {
              hasNextPage
              endCursor
            }
          }
        }
        """
        variables = {
            "updatedAtMin": updated_at_min if lastUpdate.get("existed") else None,
            "first": 250
        }

        try:
            data = execute_graphql(url, headers, query, variables)
            products = data['data']['products']['edges']
            for product_edge in products:
                product = product_edge['node']

                # Convert product details
                description = product.get('descriptionHtml', '')
                convertedProduct = convertProduct(
                    uid=uid,
                    shopId=shopId,
                    platformId=shop.get('platformId'),
                    enterpriseId=shop.get('enterpriseId'),
                    platformProductId=product.get('id'),
                    name=product.get('title'),
                    description=description,
                    createdAt=datetime.fromisoformat(product.get('createdAt')),
                    updatedAt=SERVER_TIMESTAMP,
                    tags=product.get('tags', []),
                    price=None,
                    images=[
                        convertImage(
                            url=image['node']['originalSrc'],
                            primary=image['node']['position'] == 1,
                            id=image['node']['id']
                        )
                        for image in product.get('images', {}).get('edges', [])
                    ]
                )

                # Convert variants
                variants = product.get('variants', {}).get('edges', [])
                convertedVariants = []
                for variant_edge in variants:
                    variant = variant_edge['node']
                    properties = [
                        convertProperty(name=opt['name'], value=opt['value'])
                        for opt in variant.get('selectedOptions', [])
                    ]
                    convertedVariant = convertVariant(
                        id=variant['id'],
                        price=variant['price'],
                        sku=variant['sku'],
                        properties=properties,
                        inventory_item_id=variant['inventoryItem']['id']
                    )
                    convertedVariants.append(convertedVariant)

                # Save the product and its variants
                updates.append(saveProduct(convertedProduct, convertedVariants))

            saveProductsLastUpdated(shopId, len(products), timestamp=lastOrderTimestamp)

            return f"Products Updated => {len(updates)}"

        except Exception as e:
            saveError(uid, "Shopify/Products/updateShopProducts", str(e), error=dict(shopId=shopId, lastUpdate=lastUpdate))
            return str(e)

    return None

def updateVariantSku(url, headers, variant_id, sku):
    """Update SKU for a Shopify variant using GraphQL."""
    mutation = """
    mutation($variantId: ID!, $sku: String!) {
      productVariantUpdate(input: {id: $variantId, sku: $sku}) {
        productVariant {
          id
          sku
        }
        userErrors {
          field
          message
        }
      }
    }
    """
    variables = {"variantId": variant_id, "sku": sku}
    response = execute_graphql(url, headers, mutation, variables)
    errors = response['data']['productVariantUpdate']['userErrors']
    if errors:
        raise Exception(f"Errors updating variant SKU: {errors}")
    return True

def updateItemCostOnShopify(url, headers, inventory_item_id, cost):
    """Update cost for an inventory item using GraphQL."""
    mutation = """
    mutation($inventoryItemId: ID!, $cost: Float!) {
      inventoryItemUpdate(input: {id: $inventoryItemId, unitCost: {amount: $cost, currencyCode: "USD"}}) {
        inventoryItem {
          id
          unitCost {
            amount
          }
        }
        userErrors {
          field
          message
        }
      }
    }
    """
    variables = {"inventoryItemId": inventory_item_id, "cost": cost}
    response = execute_graphql(url, headers, mutation, variables)
    errors = response['data']['inventoryItemUpdate']['userErrors']
    if errors:
        raise Exception(f"Errors updating inventory cost: {errors}")
    return True




import json

from V2.functions.Shopify.main import ShopifyGraphQLClient
from V2.functions.Shops.main import Shop


def delete_all_variants(shop:Shop,productId:str, variantsIds:list[str]):
    """
    Deletes all variants of a given Shopify product.
    
    :param shop: ShopifyGraphQLClient instance
    :param product_id: Shopify Product ID (e.g., "gid://shopify/Product/1234567890")
    """
    graphql_client = ShopifyGraphQLClient(shop)
    mutation = """
    mutation bulkDeleteProductVariants($productId: ID!, $variantsIds: [ID!]!) {
        productVariantsBulkDelete(productId: $productId, variantsIds: $variantsIds) {
            product {
            id  
            title
            }
            userErrors {
            field
            message
            }
        }
        }
    """

    variables = {"variantsIds": variantsIds , "productId": productId}
    result = graphql_client.execute(mutation, variables)
        # Check for errors
    errors = result.get("data", {}).get("productVariantDelete", {}).get("userErrors", [])
    if errors:
            print(f"Error deleting variant {variantsIds}: {errors}")
    else:
            print(f"Deleted variant {variantsIds} successfully.")

    print("All variants deleted successfully.")

def getShopifyProductVariants(client: ShopifyGraphQLClient, productId: str):
    """
    Fetches all variants of a given Shopify product.

    :param shop: ShopifyGraphQLClient instance
    :param product_id: Shopify Product GID (e.g., "gid://shopify/Product/1234567890")
    :return: List of variants with their details
    """

    query = """
      query getProductVariants($productId: ID!) {
        product(id: $productId) {
          variants(first: 100) {
            edges {
              node {
                id
                title
                sku
                inventoryQuantity
                inventoryItem {
                  id
                }
              }
            }
          }
        }
      }
    """

    variables = {"productId": validate_shopify_id(productId, "Product")}
    result = client.execute(query, variables)
    # Extract variants from response
    variants = result.get("data", {}).get("product", {}).get("variants", {}).get("edges", [])
    # Format the variants listc
    formatted_variants = [
        {
            "id": v["node"]["id"],
            "title": v["node"]["title"],
            "sku": v["node"]["sku"],
            "inventoryItemId": v["node"]["inventoryItem"]["id"],
        }
        for v in variants
    ]

    return formatted_variants

# shop = Shop.get("ExKbzizKurp9hprjrT8C")
# client = ShopifyGraphQLClient(shop)
# getProductVariants(client, "6928477192277")