import json
import tempfile
import traceback
from datetime import datetime

import requests
from requests_oauthlib.oauth1_session import OAuth1Session

from configs.firebase import SERVER_TIMESTAMP, ArrayUnion, db
from functions.Applications import getAppCredentials
from functions.Enterprises import getEnterpriseById, getItemCost
from functions.Products import getProductRef, saveProduct
from functions.Response import API_Error
from functions.Shopify.Fulfillment import getFulfillmentService
from functions.Shops import getShopById
from functions.WooCommerce.Auth import wooAPI
from functions.WooCommerce.Products import createAttributes, createVariants
from V2.functions.Applications.main import Application
from V2.functions.Etsy.Products import submitToEtsy
from V2.functions.Products.main import Product, Variant
from V2.functions.Shopify.Products import delete_all_variants
from V2.functions.Shops.Auth import ENTERPRISES, PLANS
from V2.functions.Shops.main import Shop
from V2.functions.Shopify.Products import delete_all_variants, ShopifyGraphQLClient
# from V2.functions.Shopify.Locations import  updateFulfillmentLocations


apiVersion = '2023-07'
from V2.functions.Shopify.Locations import getFulfillmentService,updateFulfillmentLocations,getShopLocations
from V2.functions.Squarespace.Products import submitToSquarespace


def generate_variants(platformId:str,variants:list, listing_id=None, **kwargs):
    size_order = {"XS": 0, "S": 1, "SMALL": 1, "MEDIUM": 2,  "M": 2, "L": 3,"LARGE": 3, "XL": 4, "XXL": 5, "2XL": 5, "XXXL": 6, "3XL": 6, "XXXL": 7, "4XL": 7,"5XL": 8}
    variants = sorted(variants, key=lambda variant: size_order.get(str(variant.get("size")).upper(), -1))
    if platformId  == "1":
        formatted_variants =  []
        size_property_id = 513
        color_property_id = 514
        mappings = {}
        for variant in variants:
            size =  variant.get("size")
            color = variant.get("color")
            sku = variant.get("sku")
            variant = dict(
                sku = variant.get("sku"),
                property_values = [
                    dict(
                        property_id = size_property_id,
                        property_name = "Size",
                        display_name="Size",
                        values = [size]
                    ),
                    dict(
                        property_id = color_property_id,
                        property_name = "Primary Color",
                        display_name = "Primary Color",
                        values = [color]
                    )
                    ],
                offerings = [dict(price=float(variant.get("price")), quantity=variant.get("quantity", 100), is_enabled=1, is_deleted=0)]
            )
            formatted_variants.append(variant)
            # print(variant)
        return (dict(listing_id=int(listing_id), products = json.dumps(formatted_variants), price_on_property=[size_property_id], sku_on_property=f"{size_property_id},{color_property_id}"))
    if platformId == "2":
        formatted_variants = []
        unique_variants = set()  # To track unique (color, size) pairs
        colors = set()
        sizes = set()

        for variant in variants:
            size = variant.get("size", "").strip()
            color = variant.get("color", "").strip()
            sku = variant.get("sku")
            price = str(variant.get("price"))

            # Ensure the (color, size) combination is unique
            if (color, size) not in unique_variants:
                formatted_variants.append({
                    "option1": color,
                    "option2": size,
                    "price": price,
                    "sku": sku,
                })
                unique_variants.add((color, size))
                colors.add(color)
                sizes.add(size)

        # Format options for Shopify GraphQL API
        options = [
            {"name": "Color", "values": list(colors)},
            {"name": "Size", "values": list(sizes)}
        ]

        return {
            "variants": formatted_variants,
            "options": options
        }
    # elif platformId == "2":
    #     formatted_variants = []
    #     colors = []
    #     sizes = []
    #     for variant in variants:
    #         size =  variant.get("size", "")
    #         color = variant.get("color")
    #         sku = variant.get("sku")
    #         # if not (size in sizes and color in colors):
    #         if not any(v.get("option2") == size and v.get("option1") == color for v in formatted_variants):
    #             formatted_variants.append(dict(
    #                 option1 = color,
    #                 option2 = size,
    #                 price = str(variant.get("price")),
    #                 sku=sku,
    #                 # option = f"{color} - {size}",
    #             ))
    #             colors.append(color)
    #             sizes.append(size)
    #     options = [
    #         dict(
    #             name="Color",
    #             values=list(set(colors))
    #         ),
    #         dict(
    #             name="Size",
    #             values=list(set(sizes))
    #         )
    #     ]
    #     return (dict(
    #         variants=formatted_variants,
    #         options=options
    #         ))
    elif platformId == "3":
        colors =[]
        sizes = []
        mappings = {}
        formatted_variants = []
        for variant in variants:
            color = variant.get("color")
            size = variant.get("size")
            sku = variant.get('sku')
            mapping = variant.get("mapping")
            mappings[str(sku)] = mapping
            colors.append(color)
            sizes.append(size)
            formatted_variants.append(dict(
                regular_price=str(variant.get("price")),
                sku=sku,
                attributes = [
                    dict(
                        name="Size",
                        variation=True,
                        option=size,
                    ),
                     dict(
                        name="Color",
                        variation=True,
                        option=color,
                    )
                ]
            ))
        attributes = [dict(
                name="Size",
                variation=True,
                visible=True,
                options=list(set(sizes))
            ),
            dict(
                name="Color",
                variation=True,
                visible=True,
                options=list(set(colors))
            )]       
        return (attributes, mappings, formatted_variants)
    return None

# def submitToEtsy(uid:str,enterpriseId:str, shop:dict, title:str, description:str, price:float, quantity:int, taxonomy_id:int, tags:list,
#     state: str,variants:list,  shipping_template_id:int, images = []) -> tuple:
#     app = getAppCredentials("1"+enterpriseId)
#     oauth = OAuth1Session(app.get("apiKey"), app.get('apiSecret'), shop.get('oauthToken'), shop.get("oauthTokenSecret"))
#     listings_url  = "https://openapi.etsy.com/v2/listings"
#     listing = dict(
#         title=title,
#         description=description,
#         price=price if price else min([float(v.get('price')) for v in variants]),
#         quantity=quantity, 
#         taxonomy_id=int(taxonomy_id),
#         tags=",".join(tags),
#         who_made="i_did",
#         is_supply=False,
#         when_made="made_to_order",
#         recipient="not_specified",
#         state=state,
#         shipping_template_id= shipping_template_id
#     )
#     request = oauth.post(listings_url, params=listing)
#     if request.status_code == 201:
#         listing = request.json().get("results")[0]
#         listing_id = str(listing.get('listing_id'))
#         variants = generate_variants("1", variants, listing_id)
#         inventory_request = oauth.put(f"{listings_url}/{listing_id}/inventory", data = variants)
#         if inventory_request.status_code != 200:
#             deletedRequest = oauth.delete(f"{listings_url}/{listing_id}")
#             raise API_Error(inventory_request.text, 400, meta= dict(message = inventory_request.text, deleteMessage = deletedRequest.text))
#         rank = 1
#         path, image_paths = tempImages(images)
#         for image in image_paths:
#             with open(image.get("image"), 'rb') as f:
#                 files = {"image": f}
#                 image_request = oauth.post(f"{listings_url}/{listing_id}/images", files = files, params={"rank":rank})
#                 if image_request.status_code != 201:
#                     deletedRequest = oauth.delete(f"{listings_url}/{listing_id}")
#                     raise API_Error("Image upload failed. ", 400, meta=dict(message = image_request.text, deleteMessage = deletedRequest.text))
#                 rank += 1
#         if inventory_request.status_code == 200:
#             etsy_variants = {str(v.get('sku')): str(v.get('product_id')) for v in inventory_request.json().get("results", {}).get("products", [])}
#             return listing_id, etsy_variants
#         raise API_Error(inventory_request.text, inventory_request.status_code)
#     raise API_Error(request.text, request.status_code)

def tempImages(images:list):
    path = tempfile.mkdtemp()
    image_paths = []
    for image in images:
        src = image.get('url')
        name = image.get("name")
        content = requests.get(src).content
        image_name = f"{path}/{name}"
        with open(image_name, "wb") as image_file:
            image_file.write(content)
            image_paths.append(dict(name=name, image=image_name))
    return (path, image_paths)


def submitProduct(params:dict):
    currentUser = params.get('currentUser')
    uid, enterpriseId = currentUser.get('uid'), currentUser.get("enterpriseId")
    manualProducts = params.get('manualProducts', [])
    if not manualProducts: raise API_Error("No Products Selected.", 400)
    shopId = params.get('shopId') 
    shop = Shop.get(shopId)
    platformId = shop.platformId
    enterprise = getEnterpriseById(enterpriseId)
    planId = enterprise.get('planId')
    app = Application.get(platformId+("zNAlxdaZG6hKf6vexv6ljqHyP8i1" if planId in PLANS or enterpriseId in ENTERPRISES else enterpriseId))
    if not shop: raise API_Error("Shop not found.", 404, dict(shopId=shopId))
    responses = { }
    for manualProduct in manualProducts:
        manualProductId = manualProduct.get('id')
        platformProductId = None
        platformVariants = None
        taxonomyId = int(manualProduct.get('taxanomyId')) if platformId == "1" else None
        shippingTemplateId = int(manualProduct.get('shippingTemplateId')) if platformId == "1" else None
        try:
            manualProductRef = db.collection("manualProducts").document(manualProductId).get()
            if not manualProductRef.exists: raise API_Error("Selected product not found.", 404, dict(id=manualProductId))
            manualProduct = manualProductRef.to_dict()
            # if shopId in manualProduct.get("activeShops", []):
            # raise API_Error("This product is already active in selected shop.")
            placements = [p.to_dict() for p in manualProductRef.reference.collection("placements").get()]
            variations = [{"sku":v.id, **v.to_dict()} for v in manualProductRef.reference.collection('variations').get()]
            variantsMapping = {v.id: v.to_dict() for v in manualProductRef.reference.collection("variantsMapping").get()}
            blankProductIds = manualProduct.get("productMapping").get("blankProductIds")
            weights = {}
            for blankProductId in blankProductIds: weights.update(getBlankVariantWeights(blankProductId)) 
            variant_weights = {}
            for variant_id, variant_data in variantsMapping.items():
                blank_product_id = variant_data.get("blankProductId")
                blank_variant_id = variant_data.get("blankVariantId")
                if blank_product_id and blank_variant_id:
                    key = f"{blank_product_id}{blank_variant_id}"
                    if key in weights: variant_weights[variant_id] = weights[key]
            images = manualProduct.get('images', []) if manualProduct.get('images', []) else manualProduct.get("productDetails", {}).get("avatars", [])
            price = manualProduct.get('price')
            colorImages = {doc.id: doc.to_dict().get('images', []) for doc in manualProductRef.reference.collection("colorImages").get()}
            if platformId == "1":
                response = submitToEtsy(
                    uid=uid,
                    app=app,
                    shop=shop,
                    title=manualProduct.get('name'),
                    description= manualProduct.get('productDetails',{}).get('description', ""),
                    price=manualProduct.get('price', 10),
                    quantity=params.get('quantity', 100),
                    taxonomy_id=taxonomyId,
                    tags=manualProduct.get('tags'),
                    state="active",
                    variants=variations,
                    shipping_template_id=shippingTemplateId,
                    images=images,
                    item_weight=5,
                    item_weight_unit="oz",
                    item_length=15,
                    item_width=12,
                    item_height=2, 
                    item_dimensions_unit="in",
                    colorImages=colorImages
                )
                platformProductId, platformVariants = response
            elif platformId == "2":
                response = submitToShopify(
                    name=manualProduct.get('name'),
                    description=manualProduct.get('productDetails',{}).get('description', ""),
                    images=images,
                    shop=shop,
                    tags=manualProduct.get('tags'),
                    variants=variations,
                    colorImages=colorImages,
                    price=price,
                    variantsMapping=variantsMapping,
                    weights=variant_weights,
                    currentUser=currentUser
                )
                platformProductId, platformVariants = response


                # Optional: get productId from params or existing logic
                # if platformProductId:
                #     print('platformProductId',platformProductId)
                #     print('manualProduct['']',manualProduct['id'])


                #     client = ShopifyGraphQLClient(shop)

                #     updateFulfillmentLocations(
                #         client=client,
                #         productId=manualProduct['id'],
                #         platformProductId=platformProductId
                #     )

            elif platformId == "3":
                response = submitToWoocommerce(
                    name=manualProduct.get('name'),
                    description=manualProduct.get('description', ""),
                    shop=shop.to_dict(),
                    colorImages=colorImages,
                    tags=manualProduct.get('tags',[]),
                    variants=variations,
                )
                platformProductId, platformVariants = response


            elif platformId == "10":
                response = submitToSquarespace(
                    name=manualProduct.get('name'),
                    description=manualProduct.get('description', ""),
                    shop=shop,
                    colorImages=colorImages,
                    tags=manualProduct.get('tags',[]),
                    variants=variations,
                )
                platformProductId, platformVariants = response
            elif platformId == "13":
                response = addToPopupStore(
                    name=manualProduct.get('name'),
                    description=manualProduct.get('description', ""),
                    shop=shop,
                    images=images,
                    tags=manualProduct.get('tags',[]),
                    variants=[Variant.from_dict(v.to_dict()) for v in manualProductRef.reference.collection("variants").get()],
                )
                platformProductId, platformVariants = response
            else:
                raise API_Error("Unsupported platform.")
            if platformProductId and platformVariants:
                productMapping = manualProduct.get("productMapping")
                del manualProduct['productDetails']
                del manualProduct['productMapping']
                del manualProduct['selectedBlankNicknames']
                if manualProduct.get("activeShops"):
                    del manualProduct['activeShops']
                if manualProduct.get("activeProducts"):
                    del manualProduct['activeProducts']
                productId = getProductRef(platformId, shopId, platformProductId)
                manualProduct['id'] = productId
                manualProduct['platformProductId'] = platformProductId
                manualProduct['platformId'] = platformId
                manualProduct['shopId'] = shopId
                manualProduct['createdAt'] = SERVER_TIMESTAMP
                manualProduct['updatedAt'] = SERVER_TIMESTAMP
                manualProduct['parentProductId'] = manualProductId
                productMapping['id'] = productId
                convertedVariants = []
                variants = {v.id:v.to_dict() for v in manualProductRef.reference.collection("variants").get()}
                mappedVariants = []
                for sku in platformVariants.keys():
                    variantId = str(platformVariants.get(sku))
                    variantMapping = variantsMapping.get(sku)
                    variant = variants.get(sku)
                    variant['id'] = variantId
                    variantMapping['id'] = variantId
                    convertedVariants.append(variant)
                    mappedVariants.append(variantMapping)
                productId = saveProduct(manualProduct, convertedVariants)
                saveProductMapping(productMapping, mappedVariants, placements, colorImages=colorImages)
                manualProductRef.reference.update(dict(
                    activeShops = ArrayUnion([shopId]),
                    activeProducts = ArrayUnion([productId])
                ))
                responses[manualProductId]= dict(
                    status_code = 200,
                    message=f"Listing added to {shop.name}.",
                    success=True,
                    id=manualProductId,
                    productId=productId)
        except API_Error as e:
            print(e.message)
            responses[manualProductId]= dict(
                id=manualProductId,
                message=e.message,
                meta=e.meta,
                status_code = e.status_code,
                success=False,
                productId=None
            )
        except Exception as e:
            print(e)
            print(traceback.format_exc())
            responses[manualProductId]= dict(
                id=manualProductId,
                message=str(e),
                meta={},
                status_code=500,
                success=False,
                productId=None
            )
    # if any([not r.get('success') for r in responses.values()]): raise API_Error("Some products could not be listed.", 400, dict(responses=responses))
    return dict(responses=responses)

def getBlankVariantWeights(blankProductId):
    blankVariants = db.collection(f"blankProducts/{blankProductId}/blankVariants").get()
    return {
        str(blankProductId+blankVariant.id): blankVariant.to_dict().get("weight") for blankVariant in blankVariants
    }

import json

from V2.functions.Shopify.main import (  # Import Shopify GraphQL Client
    ShopifyGraphQLClient, shopifyGid, shopifyNumId)


# def submitToShopify(
#                     shop: Shop,
#                     name,
#                     description,
#                     tags,
#                     variants,
#                     images,
#                     colorImages={},
#                     price=None,
#                     variantsMapping={},
#                     weights={}
#         ) -> tuple:

#     # Initialize Shopify GraphQL Client
#     graphql_client = ShopifyGraphQLClient(shop)

#     # Generate formatted variants
#     generated_variants = generate_variants("2", variants)

#     # **Create New Product in Shopify (without variants)**
#     mutation = """
#         mutation productCreate($input: ProductInput!) {
#             productCreate(input: $input) {
#                 product {
#                 id
#                 title
#                 variants(first: 10) {
#                     edges {
#                             node {
#                                 id
#                                 title
#                             }
#                         }
#                     }
#                 }
#                 userErrors {
#                 field
#                 message
#                 }
#             }
#         }
#     """

#     # **Prepare variables for Shopify API**
#     variables = {
#         "input": {
#             "title": name,
#             "descriptionHtml": description,  # ✅ Correct for latest API
#             "tags": tags,
#             "productOptions":[
#                 {
#                     "name": "Size",
#                      "values":[ {
#                         "name": value
#                     } for value in generated_variants.get("options")[1].get("values")]
#                 },
#                 {
#                     "name": "Color",
#                     "values":[ {
#                         "name": value
#                     } for value in generated_variants.get("options")[0].get("values")]
#                 }
#             ],
#             "status": "ACTIVE",  # ✅ Correct for latest API
#             # "options": [opt["name"] for opt in generated_variants.get("options", [])],
#             # "images": [{"src": image.get("url")} for image in images] if images else []
#         }
#     }

#     # **Execute GraphQL request to create product**
#     result = graphql_client.execute(mutation, variables)
#     # **Check for errors**
#     errors = result.get("data", {}).get("productCreate", {}).get("userErrors", [])
#     if errors:
#         print("ERRORS: ", errors)
#         raise API_Error(str(errors), 400)

#     # **Extract product ID**
#     product_id = result["data"]["productCreate"]["product"]["id"]
#     variants = [v.get("node").get("id") for v in result["data"]["productCreate"]["product"]["variants"]['edges']]
#     # delete_all_variants(shop, product_id, variants)
#     # **Prepare Variants for Bulk Creation**
#     # unique_variants = {}
#     # for variant in generated_variants.get("variants", []):
#     #     key = f"{variant.get('option1')}-{variant.get('option2')}"hh
#     #     if key not in unique_variants:
#     #         sku = variant.get("sku")
#     #         unique_variants[key] = {
#     #             "sku": sku,
#     #             "price": variant.get("price"),
#     #             "options": [variant.get('option1'), variant.get('option2')],
#     #             "weight": weights.get(sku, 0),
#     #             "weightUnit": "OZ"
#     #         }
#     # variants_list = list(unique_variants.values())

#     # **Create Product Variants in Bulk**
#     mutation = """
#        mutation ProductVariantsCreate($media:[CreateMediaInput!], $productId:ID!, $variants: [ProductVariantsBulkInput!]!) {
#         productVariantsBulkCreate(media:$media, productId: $productId, variants: $variants, strategy: REMOVE_STANDALONE_VARIANT) {
#             productVariants {
#                 id
#                 title
#                 sku
#                 selectedOptions {
#                     name
#                     value
#                 }
#                 inventoryItem {
#                  id
#                 }
#             }
#             userErrors {
#                 field
#                 message
#             }
#         }
#     }
#     """
#     fulfillmentService = getFulfillmentService(graphql_client) 
#     variantImages = {color: [i.get("url") for i in images] for color, images in colorImages.items()}
#     variables = {
#         "productId": product_id,
#         "media":[{"originalSource": image, "mediaContentType": "IMAGE"} for image in sum(variantImages.values(), [])],
#         "variants": [
#             {
#                 # "productId": v["productId"],
#                 # "sku": v["sku"],
#                 "mediaSrc": variantImages.get(v.get('option1'), [])[0] if variantImages.get(v.get('option1'), []) else [],
#                 "price": v["price"],
#                 "optionValues": [
#                     {
#                         "optionName": "Size",
#                         "name": v.get('option2')
#                     },
#                     {
#                         "optionName": "Color",
#                         "name": v.get('option1')
#                     }
#                 ],
#                 "inventoryPolicy": "CONTINUE",
#                 "inventoryQuantities": {
#                     "availableQuantity": 100,
#                     "locationId": fulfillmentService.get("location").get("id")
#                 }, 
#                 "inventoryItem": {
#                     "cost": v["price"],
#                     "sku": v["sku"],
#                     "tracked": True,
#                     "measurement":{
#                         "weight": {
#                             "value":float(weights.get(v["sku"], 0)),
#                             "unit": "OUNCES"
#                         },
#                     }
#                 },
#             } for v in generated_variants.get("variants")
#         ]
#     }
#     # **Execute GraphQL request to create variants separately**
#     result = graphql_client.execute(mutation, variables)
#     # **Check for errors in variant creation**
#     errors = result.get("data", {}).get("productVariantsBulkCreate", {}).get("userErrors", [])
#     if errors:
#         print("VARIANT ERRORS: ", errors)
#         raise API_Error(str(errors), 400)
    

#         # Activate inventory at the location
#     activate_inventory_mutation = """
#     mutation inventoryActivate($inventoryItemId: ID!, $locationId: ID!) {
#       inventoryActivate(inventoryItemId: $inventoryItemId, locationId: $locationId, ) {
#         inventoryLevel {
#           id
#         }
#         userErrors {
#           field
#           message
#         }
#       }
#     }
#     """
#     # Activate each inventory item
#     for v in result["data"]["productVariantsBulkCreate"]["productVariants"]:
#         inventory_item_id = v.get("inventoryItem").get("id")
#         variables = {
#             "inventoryItemId": inventory_item_id,
#             "locationId": fulfillmentService.get("location").get("id"),
#             "stockAtLegacyLocation": True ,
#         }
#         activation_result = graphql_client.execute(activate_inventory_mutation, variables)
#         print("INVENTORY ACTIVATE RESULT:", activation_result)

#     # **Extract created variant IDs**
#     variants_map = {v["sku"]: shopifyNumId(v["id"]) for v in result["data"]["productVariantsBulkCreate"]["productVariants"]}
#     publishProductToOnlineStore(graphql_client, product_id)
#     return shopifyNumId(product_id), variants_map
def submitToShopify(
    shop: Shop,
    name,
    description,
    tags,
    variants,
    images,
    colorImages={},
    price=None,
    variantsMapping={},
    weights={},
    currentUser=None
) -> tuple:

    # from V2.functions.Shopify.main import getShopLocations, ShopifyGraphQLClient
    # from V2.functions.Shopify.Products import publishProductToOnlineStore
    from V2.Params import Params
    from functions.Response import API_Error

    graphql_client = ShopifyGraphQLClient(shop)

    # Generate formatted variants
    generated_variants = generate_variants("2", variants)

    # Create Product
    product_create_mutation = """
        mutation productCreate($input: ProductInput!) {
            productCreate(input: $input) {
                product {
                    id
                    title
                    variants(first: 10) {
                        edges {
                            node {
                                id
                                title
                            }
                        }
                    }
                }
                userErrors {
                    field
                    message
                }
            }
        }
    """

    product_variables = {
        "input": {
            "title": name,
            "descriptionHtml": description,
            "tags": tags,
            "productOptions": [
                {
                    "name": "Size",
                    "values": [{"name": value} for value in generated_variants.get("options")[1].get("values")]
                },
                {
                    "name": "Color",
                    "values": [{"name": value} for value in generated_variants.get("options")[0].get("values")]
                }
            ],
            "status": "ACTIVE"
        }
    }

    result = graphql_client.execute(product_create_mutation, product_variables)
    errors = result.get("data", {}).get("productCreate", {}).get("userErrors", [])
    if errors:
        raise API_Error(str(errors), 400)

    product_id = result["data"]["productCreate"]["product"]["id"]

    # Get native Shopify locations only
    params = Params(
        currentUser=currentUser,
        hostname="shopify",
        id=shop.id,
        args={"shopId": shop.id}
    )
    locations = getShopLocations(params)
    location_ids = [f"gid://shopify/Location/{loc['id']}" for loc in locations if loc.get("active") and not loc.get("legacy")]

    variantImages = {color: [i.get("url") for i in images] for color, images in colorImages.items()}

    # Create Variants
    variants_create_mutation = """
       mutation ProductVariantsCreate($media:[CreateMediaInput!], $productId:ID!, $variants: [ProductVariantsBulkInput!]!) {
        productVariantsBulkCreate(media:$media, productId: $productId, variants: $variants, strategy: REMOVE_STANDALONE_VARIANT) {
            productVariants {
                id
                title
                sku
                selectedOptions {
                    name
                    value
                }
                inventoryItem {
                    id
                }
            }
            userErrors {
                field
                message
            }
        }
    }
    """

    variant_inputs = []
    for v in generated_variants.get("variants"):
        inventory_quantities = [
            {
                "availableQuantity": 50,
                "locationId": loc_id
            } for loc_id in location_ids
        ]

        variant_inputs.append({
            "mediaSrc": variantImages.get(v.get('option1'), [])[0] if variantImages.get(v.get('option1')) else [],
            "price": v["price"],
            "optionValues": [
                {"optionName": "Size", "name": v.get('option2')},
                {"optionName": "Color", "name": v.get('option1')}
            ],
            # "fulfillmentService": "manual",
            "inventoryPolicy": "CONTINUE",
            "inventoryQuantities": inventory_quantities[0],  # Use one native location initially
            # "fulfillmentService": "manual",
            "inventoryItem": {
                "cost": v["price"],
                "sku": v["sku"],
                "tracked": True,
                "measurement": {
                    "weight": {
                        "value": float(weights.get(v["sku"], 0)),
                        "unit": "OUNCES"
                    }
                }
            },
        })

    variant_variables = {
        "productId": product_id,
        "media": [{"originalSource": img, "mediaContentType": "IMAGE"} for img in sum(variantImages.values(), [])],
        "variants": variant_inputs
    }

    variant_result = graphql_client.execute(variants_create_mutation, variant_variables)
    errors = variant_result.get("data", {}).get("productVariantsBulkCreate", {}).get("userErrors", [])
    if errors:
        raise API_Error(str(errors), 400)

    # Activate inventory only at native Shopify locations
    activate_mutation = """
    mutation inventoryActivate($inventoryItemId: ID!, $locationId: ID!) {
      inventoryActivate(inventoryItemId: $inventoryItemId, locationId: $locationId) {
        inventoryLevel {
          id
        }
        userErrors {
          field
          message
        }
      }
    }
    """
    print('variant_result',variant_result)
    data = variant_result.get("data", {})
    if not data:
        raise API_Error("Shopify returned no data: " + str(variant_result), 400)

    variants_data = data.get("productVariantsBulkCreate", {}).get("productVariants", [])
    for variant in variants_data:
        inventory_item_id = variant.get("inventoryItem").get("id")
        for loc_id in location_ids:
            activation_result = graphql_client.execute(activate_mutation, {
                "inventoryItemId": inventory_item_id,
                "locationId": loc_id
            })
            print("Activated:", activation_result)

    variants_map = {v["sku"]: shopifyNumId(v["id"]) for v in variant_result["data"]["productVariantsBulkCreate"]["productVariants"]}
    publishProductToOnlineStore(graphql_client, product_id)

    return shopifyNumId(product_id), variants_map

def getOnlineStorePublicationId(client: ShopifyGraphQLClient):
    query = """
    query {
      publications(first: 10) {
        nodes {
          id
          name
        }
      }
    }
    """
    result = client.execute(query)
    for pub in result.get("data", {}).get("publications", {}).get("nodes", []):
        if pub.get("name") == "Online Store":
            return pub.get("id")
    raise Exception("Online Store publication ID not found.")

def publishProductToOnlineStore(client: ShopifyGraphQLClient, productGid: str):
    # Replace this with the actual publication ID for "Online Store"
    onlineStorePublicationId = getOnlineStorePublicationId(client)

    mutation = """
    mutation productPublish($input: ProductPublishInput!) {
        productPublish(input: $input) {
            product {
                id
            }
            productPublications {
                channel {
                    name
                }
                isPublished
            }
            userErrors {
                    field
                    message
                }
            }
        }
    """

    variables = {
        "input": {
            "id": productGid,
            "productPublications": [
                dict(
                    publicationId=onlineStorePublicationId,
                )
            ]
        }
    }

    try:
        result = client.execute(mutation, variables)
        errors = result.get("data", {}).get("publishablePublish", {}).get("userErrors", [])
        if errors:
            print(f"❌ Failed to publish product {productGid}: {errors}")
        else:
            print(f"✅ Product {productGid} published to Online Store.")
    except Exception as e:
        print(f"❌ Exception publishing product {productGid}: {str(e)}")

# def submitToShopify(
#                     shop,
#                     name,
#                     description,
#                     tags,
#                     variants,
#                     images,
#                     colorImages={},
#                     price=None,
#                     variantsMapping={},
#                     weights={}
#         ) -> tuple:
#     shopId = shop.get('id')
#     enterpriseId = shop.get('enterpriseId')
#     url = shop.get("url")
#     listing_url = f"{url}/admin/api/{apiVersion}/products.json"
#     headers = {'X-Shopify-Access-Token': shop.get("accessToken"), "Content-Type": "application/json"}
#     variantColors = {}
#     for variant in variants:
#         color = variant.get('color')
#         currentVariants = variantColors.get(color, [])
#         currentVariants.append(variant.get("id"))
#         variantColors[color] = currentVariants

#     # Generate variants data with weights included
#     generated_variants = generate_variants("2", variants)
#     print(generated_variants)
#     # Update the generated variants with weights
#     for variant in generated_variants.get("variants", []):
#         sku = variant.get("sku")
#         if sku in weights:
#             variant["weight"] = weights[sku]
#             variant["weight_unit"] = "oz" 
#     product = dict(
#         title=name,
#         body_html=description,
#         published=True,
#         tags=tags,
#         images=[dict(src=image.get('url')) for image in images] if not colorImages else [],
#         variants=generated_variants.get("variants", [])
#     )

#     request = requests.post(listing_url, data=json.dumps(dict(product=product)), headers=headers)

#     if request.status_code == 201:
#         listing = request.json().get("product")
#         platformProductId = str(listing.get("id"))
#         items = listing.get('variants')

#         fulfillmentService = getFulfillmentService(shopId)
#         if not fulfillmentService:
#             print("No fulfillment service found.")
#             fulfillmentService = createFulfillmentService(dict(shopId=shopId, currentUser=dict(
#                 uid=shop.get('uid'),
#                 enterpriseId=enterpriseId,
#                 shop=shop
#             )))

#         for item in items:
#             inventory_item_id = item.get("inventory_item_id")
#             connectionInventoryLocation(url, headers, inventory_item_id, fulfillmentService.get('location_id'))

#             variantMapping = variantsMapping.get(item.get("sku"))
#             cost = getItemCost(enterpriseId, variantMapping.get('blankProductId'), variantMapping.get('blankVariantId'))
#             if not cost:
#                 cost = 0

#             from functions.Shopify.Products import updateItemCostOnShopify
#             updateItemCostOnShopify(url, headers, inventory_item_id, cost)

#         # Handle color images
#         for color in colorImages:
#             if color == "default":
#                 continue
#             thisColorImages = colorImages.get(color)
#             skus = variantColors.get(color, variantColors.get(str(color).replace("-", "/"), []))
#             variantIds = [item.get("id") for item in items if item.get("sku") in skus]
#             for image in thisColorImages:
#                 connectionVariantImage(url, headers, src=image.get('url'), productId=platformProductId, variantIds=variantIds)

#         variants = {str(v.get("sku")): str(v.get('id')) for v in listing.get('variants')}
#         return platformProductId, variants

#     data = request.json()
#     print("CREATE PRODUCT RESPONSE" , data)
#     raise API_Error(str(data.get("errors", {})), request.status_code)

# # def submitToShopify(
#                     shop,
#                     name,
#                     description,
#                     tags,
#                     variants,
#                     images,
#                     colorImages={},
#                     price=None,
#                     variantsMapping={},
#                     weights = {}
#         ) -> tuple:
#     shopId = shop.get('id')
#     enterpriseId = shop.get('enterpriseId')
#     url = shop.get("url")
#     listing_url = f"{url}/admin/api/{apiVersion}/products.json"
#     headers = {'X-Shopify-Access-Token': shop.get("accessToken"), "Content-Type": "application/json"}
#     variantColors = {}
#     for variant in variants:
#         # variant['price'] = price
#         color = variant.get('color')
#         currentVariants = variantColors.get(color, [])
#         currentVariants.append(variant.get("id"))
#         variantColors[color] = currentVariants
#     variants = generate_variants("2", variants)
#     # print([dict(src = image.get('url')) for image in images] if not colorImages else [], price)
#     product = dict(
#         title=name,
#         body_html=description,
#         published=True,
#         tags=tags,
#         images = [dict(src = image.get('url')) for image in images] if not colorImages else []
#     )
#     product.update(variants)
#     request = requests.post(listing_url,data=json.dumps(dict(product=product)),  headers=headers)
#     if request.status_code == 201:
#         listing = request.json().get("product")
#         platformProductId = str(listing.get("id"))
#         items = listing.get('variants')
#         fulfillmentService = getFulfillmentService(shopId)
#         if not fulfillmentService:
#             print("No fulfillment service found.")
#             fulfillmentService = createFulfillmentService(dict(shopId=shopId,currentUser = dict(
#                 uid = shop.get('uid'),
#                 enterpriseId=enterpriseId,
#                 shop=shop
#             )))
#         for item in items:
#             inventory_item_id = item.get("inventory_item_id")
#             connectionInventoryLocation(url, headers, inventory_item_id, fulfillmentService.get('location_id'))
#             variantMapping = variantsMapping.get(item.get("sku"))
#             cost = getItemCost(enterpriseId, variantMapping.get('blankProductId'), variantMapping.get('blankVariantId'))
#             if not cost: cost = 0
#             from functions.Shopify.Products import updateItemCostOnShopify
#             updateItemCostOnShopify(url, headers, inventory_item_id, cost)
#             # print(res)
#         # print(colorImages)
#         for color in colorImages:
#             if color == "default": continue
#             thisColorImages = colorImages.get(color)
#             skus = variantColors.get(color, variantColors.get(str(color).replace("-", "/"), []))
#             variantIds = [item.get("id") for item in items if item.get("sku") in skus]
#             for image in thisColorImages: connectionVariantImage(url, headers, src = image.get('url'), productId=platformProductId, variantIds=variantIds)
#         variants = {str(v.get("sku")):str(v.get('id')) for v in listing.get('variants')}
#         return platformProductId, variants
#     data = request.json()
#     raise API_Error(str(data.get("errors", {})), request.status_code)

def submitToWoocommerce(shop, name, description,  variants,tags=[], colorImages={}):
    url = shop.get("url")
    attributes, _, formatted_variants = generate_variants("3", variants)
    images = []
    colorSkus = {variant.get("sku"): variant.get("color") for variant in variants}
    for key, imges in colorImages.items():
        images.extend(
            dict(name=key, src= i.get('url'))for i in imges
        )
    payload =  dict(
        name=name,
        description=description,
        images=images,
        type='variable',
        attributes=attributes,
        tags =[ dict(name=tag)for tag in tags],
        regular_price = str(min(v.get("price") for v in variants))
    )
    url, key, secret = shop.get("url"), shop.get("consumerKey"), shop.get("consumerSecret")
    wcapi  = wooAPI(url, key, secret)
    atts = {}
    for attribute in attributes:
        atts.update(createAttributes(wcapi, attribute))
    data = wcapi.post("products", payload)
    variants = {}
    if data.status_code in [200, 201]:
        data = data.json()
        images = data.get("images")
        id = data.get("id")
        url = f"products/{id}/variations"
        for variant in formatted_variants:
            variant['attributes'] = [
                dict(
                    # id=atts.get(attribute.get("name")),
                    name = attribute.get("name"),
                    option=attribute.get("option"),
                ) for attribute in variant.get("attributes")
            ]
            variant_images = [dict(id = image.get("id")) for image in images if colorSkus.get(variant.get("sku")) == image.get("name")]
            variant['image'] = variant_images[0] if variant_images else None
        createdVariants = createVariants(wcapi, id, formatted_variants)
        for variant in formatted_variants:
            variants[variant.get("sku")] = createdVariants.get(variant.get("sku"))
        return str(id), variants
    raise API_Error(data.text, data.status_code)

def connectionVariantImage(url, headers, productId, variantIds, src=None, attachment=None):
    url = f"{url}/admin/api/{apiVersion}/products/{productId}/images.json"
    image=dict(variant_ids = variantIds)
    if src: image['src'] = src
    if attachment: image['attachment'] = attachment
    data = dict(image=image)
    res = requests.post(url, data=json.dumps(data), headers=headers)
    return print(res.text)

def saveProductMapping(productMapping, variantsMapping, placements= [], colorImages={}):
    id = productMapping.get('id')
    ref = db.collection("productsMapping").document(id)
    ref.set(productMapping)
    for variantMapping in variantsMapping: ref.collection("variantsMapping").document(variantMapping.get('id')).set(variantMapping)
    for placement in placements: ref.collection("placements").document(placement.get('id')).set(placement)
    for color, images in colorImages.items(): 
        ref.collection("colorImages").document(color).set(dict(images=images))
    return id

def addNewProductImage(url, header, variantId, image):
    image_url = f"{url}/admin/api/{apiVersion}/products/{variantId}/images.json"
    image_data = {
        "image": {
            "attachment": image.get('url')
        }
    }
    request = requests.post(image_url, data=json.dumps(image_data), headers=header)
    if request.status_code == 201:
        return request.json().get("image")
    data = request.json()
    raise API_Error(str(data.get("errors", {}).values()), request.status_code)


def addToPopupStore(
        name,
        description,
        shop:Shop,
        images= [],
        tags = [],
        variants = []
):
    platformProductId = str(int(datetime.now().timestamp()))
    productId = shop.platformId+shop.id+platformProductId
    product = Product(
        id=productId,
        uid=shop.uid,
        platformId="13",
        shopId = shop.id,
        enterpriseId=shop.enterpriseId,
        platformProductId=platformProductId,
        name=name,
        description=description,
        createdAt=datetime.now(),
        updatedAt=datetime.now(),
        price=min([variant.price for variant in variants]),
        images=images,
        tags=tags
    )
    product.save([Variant.from_dict(variant) for variant in variants])
    return productId, {variant.id: variant.id for variant in variants}