import json
from datetime import datetime

import requests

from configs.firebase import SERVER_TIMESTAMP, ArrayUnion, db
from functions.Products import (convertImage, convertProduct, convertProperty,
                                convertVariant, getColorImages, getProductById,
                                getProductRef, getProductsMapping,
                                getProductVariants, getProductVariantsMapping,
                                getVariantMapping, saveProduct)
from functions.products.SubmitProduct import (addToPopupStore,
                                              saveProductMapping,
                                              submitToShopify)
from functions.Response import API_Error
from functions.Shopify.Auth import apiVersion
from functions.Shopify.Fulfillment import (connectionInventoryLocation,
                                           createFulfillmentService,
                                           getFulfillmentService)
from functions.Shops import getShopById
from functions.Suppliers.BlankProducts import (getBlankProduct,
                                               getBlankVariant,
                                               getBlankVariants)
from V2.functions.Products.main import Product, Variant
from V2.functions.Products.Variants import Property
from V2.functions.Shops.main import Shop


def manualProduct(params:dict):
    # PRINT_TYPES = {
    #     '0': {
    #         'label': "Draft Image",
    #         'value': '0',
    #     },
    #     '1': {
    #         'label': "Print on Demand",
    #         'value': '1',
    #     },
    #     '2': {
    #         'label': "Customizer Product",
    #         'value': '2',
    #     },
    # };
    currentUser = params.get("currentUser")
    uid, enterpriseId = currentUser.get('uid'), currentUser.get('enterpriseId')
    productDetails = params.get("productDetails")
    selectedBlankNicknames = params.get('selectedBlankNicknames')
    variations = params.get('variations')
    variants = []
    imageIds = []
    blankProductIds = []
    doneSKUs= []
    prices = []
    price =  productDetails.get('price')
    for variation in variations:
        try:
            price = float(variation.get('price'))
        except Exception as e:
            raise API_Error("Price should be valid number. Remove any currency symbols.")
        sku= variation.get('sku')
        if not sku:
            raise API_Error("SKU is required.")
        if "/" in sku:
            raise API_Error("SKU should not contain '/'.")
        if sku in doneSKUs:
            raise API_Error("SKU must be unique for each variant.")
        doneSKUs.append(sku)
        images = variation.get("images")
        imageIds.extend([i.get("id") for i in images])
        convertedVariant = convertVariant(
                id=sku,
                price=price,
                properties=[convertProperty("Color", variation.get('color')), convertProperty("Size", variation.get("size"))],
                sku=sku
            )
        variation['id'] = sku
        mapping = variation.get('variant')
        blankProductIds.append(mapping.get("blankProductId"))
        variantMapping = dict(
            id= sku, 
            blankProductId=mapping.get("blankProductId"),
            blankVariantId = mapping.get('id'),
            images = variation.get("images", []),
            sku = sku,
            gtin = mapping.get("gtin"),
            placements=[]   ,
            decorationType = mapping.get("decorationType", variation.get("decorationType"))
        )   
        variants.append((convertedVariant, variantMapping, variation))
        prices.append(price)
    product = convertProduct(
            uid = uid,
            platformId="0",
            shopId="0"+uid,
            enterpriseId=enterpriseId,
            platformProductId=str(int(datetime.now().timestamp())),
            price = price if price else min(prices),
            name= productDetails.get('title'),
            description= productDetails.get('description'),
            createdAt=SERVER_TIMESTAMP,
            updatedAt=SERVER_TIMESTAMP,
            tags=productDetails.get("tags", []),
            images = [convertImage(image.get('url'), id=image.get('id'), primary=image.get('primary', True)) for image in productDetails.get('avatars')]
        )
    productMapping = dict(
        blankProductIds = ArrayUnion(blankProductIds),
        enterpriseId = enterpriseId,
        ignored=False,
        imageIds = ArrayUnion(imageIds),
        printOnDemand=productDetails.get('printOnDemand', product.get('printOnDemand', True)),
        decorationType=productDetails.get('decorationType', product.get('decorationType', True)),
        uid=uid,
        updatedAt=SERVER_TIMESTAMP
    )
    product['skus'] = doneSKUs
    product['productDetails'] = productDetails
    product['productMapping'] = productMapping
    # product['selectedBlankNicknames'] = selectedBlankNicknxames
    product['printType'] = productDetails.get('printType', '0')
    id = saveManualProduct(product, variants)
    product['id'] = id
    return product

def saveManualProduct(product:dict, variants:list):
    if product.get("id"):
        ref = db.document(f"manualProducts/{product.get('id')}")
        ref.set(product)
    else:
        _,ref  = db.collection("manualProducts").add(product)
    id = ref.id
    ref.update(dict(id=id))
    for variant in variants:
        convertedVariant, variantMapping, variation = variant
        variation['manualProductId'] = id
        ref.collection("variants").document(convertedVariant.get('id')).set(convertedVariant)
        ref.collection("variantsMapping").document(convertedVariant.get('id')).set(variantMapping)
        ref.collection("variations").document(convertedVariant.get('id')).set(variation)
    return id

def saveCsvProducts(product:dict, variants:list):
    ref = db.collection("manualProducts").add(product)
    _, ref = ref
    id = ref.id
    ref.update(dict(id=id))
    for variant in variants:
        convertedVariant, variantMapping, variation = variant
        variation['manualProductId'] = id
        ref.collection("variants").document(convertedVariant.get('id')).set(convertedVariant)
        ref.collection("variantsMapping").document(convertedVariant.get('id')).set(variantMapping)
        ref.collection("variations").document(convertedVariant.get('id')).set(variation)
    return id


def getProductPlacements(productId):
    ref = db.collection(f"productsMapping/{productId}/placements").get()
    return {doc.id: doc.to_dict() for doc in ref if doc.exists}

def getProductColorImages(productId):
    ref = db.collection(f"productsMapping/{productId}/colorImages").get()
    return {doc.id: doc.to_dict() for doc in ref if doc.exists}

def createManualProductFromMapping(data:dict):
    productId = data.get('productId')
    printType = data.get("printType")
    hidden = data.get("hidden")
    id = data.get("id")
    product = getProductById(productId)
    variants = getProductVariants(productId)
    productMapping,variantsMapping = getProductVariantsMapping(productId)
    placements = getProductPlacements(productId)
    colorImages = getProductColorImages(productId)
    if not all(v.get("sku") for v in variantsMapping):
        return 
    if productMapping.get("parentProductId") and not data.get("create"): 
        return
    if not (product or variants or productMapping): 
        return
    product['productDetails'] = dict(
        title = product.get('name'),
        description = product.get('description'),
        tags = product.get('tags', []),
        avatars = product.get('images', []),
        price = product.get('price', 0),
        printOnDemand = product.get('printOnDemand', True)
    )
    product['productMapping'] = productMapping
    product['selectedBlankNicknames'] = {}
    product['printType'] = printType if printType else productMapping.get('printType', '0')
    productVariants = []
    skus = []
    variantsMapping = {v.get("id"): v for v in variantsMapping}
    for variant in variants:
        variantMapping = variantsMapping.get(variant.get("id"))
        if not variantMapping: return
        sku = variantMapping.get('sku')
        blankVariant = getBlankVariant(variantMapping.get('blankProductId'),variantMapping.get('blankVariantId'))
        if not blankVariant:
            print("Cant create manual product",productId,variantMapping)
            return
        variation = dict(
            id=sku,
            images = variantMapping.get('images', []),
            variant = blankVariant,
            color = blankVariant.get('color'),
            size = blankVariant.get('size'),
            price = variant.get('price', 0),
        )
        variant['id'] = sku
        variantMapping['sku']= sku
        productVariants.append((variant, variantMapping, variation))
        skus.append(sku)
    product['skus'] = skus
    product['createdAt'] = SERVER_TIMESTAMP
    product['updatedAt'] = SERVER_TIMESTAMP
    product['hidden'] = hidden
    if id: product['id'] = id
    id = saveManualProduct(product, productVariants)
    db.collection('products').document(productId).update(dict(manualProductId=id, parentProductId=id))
    db.collection('manualProducts').document(id).update(dict(activeShops = [product.get('shopId')], activeProducts = [productId]))
    for color, data in colorImages.items(): db.collection('manualProducts').document(id).collection('colorImages').document(color).set(data)
    for placementId, data in placements.items(): db.collection('manualProducts').document(id).collection('placements').document(placementId).set(data)
    product['id'] = id
    return product

def createDraftProduct(params:dict):
    blankProductId = params.get('blankProductId')
    blankVariantIds = params.get('blankVariantIds', [])
    shopId = params.get('shopId')
    # print("Creating draft product", blankProductId, blankVariantIds, shopId)
    currentUser = params.get('currentUser')
    uid, enterpriseId = currentUser.get('uid'), currentUser.get('enterpriseId')
    blankProduct = getBlankProduct(blankProductId)
    blankVariants = getBlankVariants(blankProductId)
    # print([b.get("id") for b in blankVariants])
    if blankVariantIds: blankVariants = [blankVariant for blankVariant in blankVariants if blankVariant.get('id') in blankVariantIds]
    if not blankProduct:
        print("NO BLANK", blankProductId)
        return
    name = blankProduct.get('name')
    description = blankProduct.get('description')
    tags = blankProduct.get('tags', [])
    primaryImage = blankProduct.get('primaryImage')
    # images = [dict(src=b.get(""))blankVariants]
    shop = getShopById(shopId, True)
    if not shop: 
        print("NO SHOP")
        return
    platformId = shop.get('platformId')
    if platformId =='1': raise API_Error("Platform not supported.", 400)
    elif platformId =='2':
        formatted_variants = []
        colors = []
        sizes = []
        for variant in blankVariants:
            size =  variant.get("size", "")
            if size not in sizes:
                size =  variant.get("size", "")
                sku = variant.get("id")
                formatted_variants.append(dict(
                    option1 = size,
                    # option2 = color,
                    price = str(10),
                    sku=sku,
                ))
                # colors.append(color)
                sizes.append(size)
        options = [
            # dict(
            #     name="Color",
            #     values=colors
            # ),
            dict(
                name="Size",
                values=list(set(sizes))
            )
        ]
        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"}
        productType = blankProduct.get("type")
        # priceRules = params.get("priceRules", [])
        # for p in priceRules:
        if productType == "nester":
            options = [
                dict(
                    name="Size",
                    values=sizes
                ),
                dict(
                name="Sheet #",
                values= [str(i) for i in range(1, len(blankVariants)+1)]
            ),
            ]
            formatted_variants = [dict(option1=v.get("size"),
                                       option2=blankVariants.index(v)+1, 
                                       price="10", sku=v.get("id")) for v in blankVariants]
        # print(formatted_variants, options)
        product = dict(
            title=name,
            body_html=description,
            published=True,
            tags=tags,
            images = [dict(src=primaryImage)],
            options=options,
            variants=formatted_variants,
            # product_type= "POD Customizer",
        )
        # print(product)
        # print(product)
        request = requests.post(listing_url,data=json.dumps(dict(product=product)),  headers=headers)
        # print(request.text)
        # print(request.text if request.status_code!=201 else request.status_code)
        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,
                    shop=shop,
                    currentUser = dict(
                    uid = shop.get('uid'),
                    enterpriseId=enterpriseId,
                )))
            for item in items:
                inventory_item_id = item.get("inventory_item_id")
                res = connectionInventoryLocation(url, headers, inventory_item_id, fulfillmentService.get('location_id'))
                # print(res)
            if platformProductId and items:
                product = convertProduct(
                    uid=uid,
                    platformId=platformId,
                    shopId= shopId,
                    enterpriseId=enterpriseId,
                    platformProductId=platformProductId,
                    name=name,
                    description=description,
                    tags=tags,
                    images=[dict(url= primaryImage)],
                    price=params.get("price", 10),
                    createdAt=SERVER_TIMESTAMP,
                    updatedAt=  SERVER_TIMESTAMP,
                    type=productType
                )
                options = listing.get('options')
                convertedVariants =  []
                mappedVariants = []
                for v in items:
                    convertedVariants.append(
                        convertVariant(
                        id =str(v.get("id")),
                        price=v.get("price"),
                        sku=v.get("sku"),
                        properties=[
                        convertProperty(name = option.get('name'), id = option.get('id'), value = v.get(f'option{option.get("position")}')) for option in options
                        ]
                    )
                    )
                    mappedVariants.append(
                        dict(
                            id = str(v.get("id")),
                            sku=v.get("sku"),
                            images=[],
                            printOnDemand=False,
                            blankProductId=blankProductId,
                            blankVariantId = v.get("sku")
                        )
                    )
                productId = saveProduct(product, convertedVariants)
                productMapping = dict(
                    id = productId,
                    createdAt = SERVER_TIMESTAMP,
                    updatedAt = SERVER_TIMESTAMP,
                    blankProductIds = [blankProductId],
                    printOnDemand=False,
                    printType="2",
                    parentProductId = productId+"manual",
                )
                colorImages= {v.get("color"):v.get("images") for v in blankVariants}
                saveProductMapping(productMapping, mappedVariants, colorImages=colorImages, placements=[])
                manualProduct = createManualProductFromMapping(dict(
                    productId = productId,
                    printType = "2",
                    create=True, 
                    id=productId+"manual",
                    hidden=True
                ))
                return dict(productId=productId, platformProductId=platformProductId, res=res)
        raise API_Error(request.text, request.status_code)
    elif platformId == '13':
        convertedVariants =  []
        for v in blankVariants:
            convertedVariants.append(
                        Variant(
                            id =str(v.get("id")),
                            price=0,
                            sku=v.get("id"),
                            properties=[
                                Property(
                                    name = "Color",
                                    id = "color",
                                    value = v.get("color")
                                ),
                                Property(
                                    name = "Size",
                                    id = "size",
                                    value = v.get("size")
                                )
                            ],
                    )
                )
        productId, _ = addToPopupStore(
                    name=name,
                    description=description,
                    shop=Shop.from_dict(shop),
                    images=[dict(url= primaryImage)],
                    tags=tags,
                    variants=convertedVariants,
                )
        mappedVariants = []
        for v in convertedVariants:
            mappedVariants.append(
                        dict(
                            id = v.id,
                            sku=v.sku,
                            images=[],
                            printOnDemand=False,
                            blankProductId=blankProductId,
                            blankVariantId = v.sku
                        )
                    )
        productMapping = dict(
                    id = productId,
                    createdAt = SERVER_TIMESTAMP,
                    updatedAt = SERVER_TIMESTAMP,
                    blankProductIds = [blankProductId],
                    printOnDemand=False,
                    printType="2",
                    parentProductId = productId+"manual",
            )
        saveProductMapping(productMapping, mappedVariants)
        manualProduct = createManualProductFromMapping(dict(
                    productId = productId,
                    printType = "2",
                    create=True, 
                    id=productId+"manual"
                ))
        return dict(productId=productId)