from datetime import datetime

from configs.firebase import SERVER_TIMESTAMP, ArrayUnion, db
from functions.Invoices import convertAmount
from functions.Products import (findProduct, getColorImages,
                                getProductsMapping, getProductVariant)
from functions.Response import API_Error
from functions.Shops import getUserShops
from V2.functions.Shops.main import Shop


def convertOrder(
            uid,
            platformId,
            shopId,
            enterpriseId, 
            shippingAddress,
            createdAt, 
            updatedAt, 
            grandTotal,
            platformOrderId,
            shipped=False, 
            cancelled=False,
            currencyCode = "USD", 
            shippingCost = 0,
            totalDiscount=0, 
            totalTax = 0,
            totalPrice = 0,
            orderNumber=None,
            metadata= {},
            **kwargs
        ):
    statusTags = []
    if cancelled: statusTags= ["cancelled"]
    if shipped and not cancelled: statusTags = ["shipped"]
    convertedOrder  = dict(
        uid=uid,
        platformId=platformId,
        shopId=shopId,
        enterpriseId=enterpriseId, 
        shippingAddress=shippingAddress,
        platformOrderId=str(platformOrderId),
        createdAt=createdAt, 
        updatedAt=updatedAt, 
        grandTotal=round(float(grandTotal),2),
        grandTotalObj=convertAmount(grandTotal, currencyCode),
        shipped=bool(shipped), 
        cancelled=bool(cancelled),
        currencyCode = str(currencyCode), 
        shippingCost = round(float(shippingCost),2), 
        shippingCostObj=convertAmount(shippingCost, currencyCode),
        totalDiscount= round(float(totalDiscount),2), 
        totalDiscountObj=convertAmount(totalDiscount, currencyCode),
        totalTax = round(float(totalTax),2),
        totalTaxObj=convertAmount(totalTax, currencyCode),
        totalPrice = round(float(totalPrice),2) if totalPrice else round(float(grandTotal),2),
        totalPriceObj=convertAmount(totalPrice, currencyCode),
        orderNumber=orderNumber,
        metadata=metadata,
        statusTags=ArrayUnion(statusTags) if statusTags else [],
        **kwargs
    )
    return convertedOrder

def convertShippingAddress(name, address1, city, state, zip, country, company= None, phone=None, address2=None, email=None, countryCode=None):
    return dict(
        name= name,
        email=email,
        phone=phone,
        address1=address1,
        address2=address2,
        city=city,
        state=state,
        zip=zip,
        country=country,
        company=company,
        formattedAddress = f"{name} \n{address1} , {city} , {state} \n {zip}, {country}",
        countryCode=countryCode if countryCode else country
    )

def convertOrderItem(
        uid,
        enterpriseId,
        platformId,
        platformProductId,
        platformOrderId, 
        platformOrderItemId,
        quantity,
        price,
        variantId,
        createdAt:datetime,
        updatedAt:datetime,
        shopId,
        product=None,
        name:str=None,
        variant = {},
        shipped=False,
        cancelled=False,
        image = {},
        discount:float=0,
        total:float=0,
        tax:float=0,
        subtotal:float=0,
        printingImages = None,
        productMapping={},
        variantMapping={},
        variantProperties = [],
        ignored=False,
        images = [],
        **kwargs
    ):
    platformProductId = str(platformProductId)
    platformOrderId = str(platformOrderId)
    quantity = int(quantity)
    price = float(price) if price else 0
    variantId = str(variantId)
    platformOrderItemId = str(platformOrderItemId)
    if not product and platformId not in  ["5"]: product = findProduct(uid, platformId, platformProductId, shopId=shopId)
    productId = product.get('id')
    if not productId: productId = platformId+shopId+platformProductId
    if not name: name = product.get('name')
    if not variant:variant = getProductVariant(productId, variantId)
    if not (productMapping or variantMapping):  productMapping, variantMapping = getProductsMapping(productId, variantId)
    properties = variant.get("properties", [])
    if not variant:variant = {}
    properties.extend(variantProperties)
    if properties: variant['properties'] = properties
    colorImages = []
    if productId and variantMapping.get("blankProductId") and variantMapping.get("blankVariantId"): colorImages = getColorImages(productId,blankProductId=variantMapping.get("blankProductId"), blankVariantId=variantMapping.get("blankVariantId"))
    if colorImages: images = colorImages
    if not images: images =  product.get('images', [])
        # color = next((v.get("value") for v in variant.get("properties") if str(v.get("name", "")).lower() == "color"), None)
    if not image: image = images[0] if images else {}
    printFilePending = False
    decorationType = None
    if variantMapping: decorationType = variantMapping.get("decorationType")
    if not decorationType and productMapping: decorationType = productMapping.get("decorationType")
    if decorationType in ["3", "7"]:
        printFiles = variantMapping.get("images")
        for i in printFiles:
            if not i.get('printFile'):
                printFilePending = True
                break
    orderItem = dict(
        uid=uid,
        enterpriseId=enterpriseId,
        platformOrderId=platformOrderId,
        platformId=platformId,
        name=name, 
        productId=productId,
        purchaseOrder=False,
        image = image ,
        platformOrderItemId=platformOrderItemId,
        platformProductId=platformProductId,
        price=round(float(price),2),
        priceObj=convertAmount(price, "USD"),
        discount=round(float(discount),2),
        discountObj=convertAmount(discount, "USD"),
        total=round(float(total),2),
        totalObj=convertAmount(total, "USD"),
        tax=round(float(tax),2),
        taxObj=convertAmount(tax, "USD"),
        subtotal=round(float(subtotal),2) if subtotal else round(price*quantity, 2),
        subtotalObj=convertAmount(subtotal, "USD") if subtotal else convertAmount(price*quantity, "USD"),
        shopId=shopId, 
        quantity=int(quantity),
        variantId = variantId,
        variant = variant if variant else {},
        createdAt=createdAt,
        updatedAt=updatedAt,
        purchaseOrderData = variantMapping,
        printOnDemand=bool(productMapping.get('printOnDemand', True)),
        shipped= bool(shipped),
        cancelled= bool(cancelled),
        ignored =ignored if ignored else bool(productMapping.get('ignored')),
        draft = not bool(productMapping.get('printOnDemand', True)) and not printingImages,
        printFilePending=printFilePending,
        images=images,
        # decorationMethod = decorationType,
        decorationType=decorationType,
        **kwargs
    )
    return orderItem

def saveOrder(order, orderItems, rewrites=False, readd=False):
    platformId, shopId, platformOrderId= order.get('platformId'),order.get('shopId'),order.get('platformOrderId')
    ref = getOrderRef(shopId, platformOrderId, platformId)
    batch = db.batch()
    statusTags = []
    if all([i.get('ignored') for i in orderItems]): statusTags = ["ignored"]
    if ref and not rewrites:
        shipped, cancelled, updatedAt = order.get('shipped'), order.get('cancelled'), order.get('updatedAt')
        orderId = ref.id
        oldOrder = ref.to_dict()
        wasShipped, wasCancelled = oldOrder.get('shipped'), oldOrder.get('cancelled')
        if wasShipped or wasCancelled: return orderId
        if wasShipped: statusTags = ["shipped"]
        if wasCancelled:  statusTags = ["cancelled"]
        update = dict(
            shipped=shipped,
            cancelled=cancelled,
            updatedAt=updatedAt,
            statusTags= statusTags
        )
        # ref.reference.update(update)
        batch.update(ref.reference, update)
        orderItems = db.collection("orderItems").where("orderId", "==", orderId).get()
        for orderItem in orderItems:
            update['variant'] = orderItem.get("variant")
            # orderItem.reference.update(update)
            batch.update(orderItem.reference, update)
    elif ref and rewrites:
        oldOrder = ref.to_dict()
        wasShipped, wasCancelled = oldOrder.get('shipped'), oldOrder.get('cancelled')
        orderId = ref.id
        if wasShipped or wasCancelled: return orderId
        order['id'] = orderId
        anyDraft = []
        productIds = []
        itemIds = []
        i = 1
        for orderItem in orderItems:
            orderItem['orderId'] = orderId
            orderItem['index'] = i
            orderItemId = f"{orderId}{orderItem.get('platformOrderItemId')}"
            orderItem['id'] = orderItemId
            productIds.append(orderItem.get('productId'))
            itemIds.append(orderItemId)
            anyDraft.append(orderItem.get('draft'))
            # db.collection("orderItems").document(orderItemId).set(orderItem, merge=not readd)
            batch.set(db.collection("orderItems").document(orderItemId), orderItem, merge=not readd)
            i+=1
        order["itemIds"] = itemIds
        order["productIds"] = productIds
        order["draft"] = any(anyDraft)
        if readd: order['mappedItems'] = itemIds
        if any(anyDraft): statusTags = ["draft"]
        if wasShipped: statusTags = ["shipped"]
        if wasCancelled: statusTags = ["cancelled"]
        order['statusTags'] = statusTags
        # ref.reference.set(order, merge=not readd)
        batch.set(ref.reference, order, merge=not readd)
    else:
        _, ref = db.collection('orders').add(order)
        orderId = ref.id
        anyDraft = []
        productIds = []
        itemIds = []
        i = 1
        for orderItem in orderItems:
            orderItem['orderId'] = orderId
            orderItem['index'] = i
            orderItemId = f"{orderId}{orderItem.get('platformOrderItemId')}"
            orderItem['id'] = orderItemId
            productIds.append(orderItem.get('productId'))
            itemIds.append(orderItemId)
            anyDraft.append(orderItem.get('draft'))
            # db.collection("orderItems").document(orderItemId).set(orderItem, merge=True)
            batch.set(db.collection("orderItems").document(orderItemId), orderItem, merge=True)
            i+=1
        if any(anyDraft): statusTags = ["draft"]
        batch.set(
            ref, 
            dict(
                id=orderId,
                productIds = ArrayUnion(productIds) if productIds else [],
                itemIds = ArrayUnion(itemIds) if itemIds else [],
                draft = any(anyDraft),
                printFilePending= any([i.get('printFilePending') for i in orderItems]),
                statusTags=statusTags,
            ),
            merge=True
        )
        # ref.set(dict(id=orderId, productIds = ArrayUnion(productIds) if productIds else [], itemIds = ArrayUnion(itemIds) if itemIds else [], draft = any(anyDraft)), merge=True)
    batch.commit()
    return orderId

def deleteOrder(orderId):
    try:
        # Delete the order from the 'orders' collection
        orderId=str(orderId)
        order_ref = db.collection('orders').document(orderId)
        order_ref.delete()

        # Delete associated order items from the 'orderItems' collection
        order_items = db.collection('orderItems').where('platformOrderId', '==', orderId).get()
        for order_item in order_items:
            order_item.reference.delete()

        print(f"Order {orderId} and associated order items deleted successfully.")

    except Exception as e:
        print(f"Error deleting order {orderId} and associated order items: {e}")

def getOrderRef(shopId, platformOrderId,platformId):
    ref = db.collection('orders').where('platformOrderId', '==', platformOrderId).where('platformId', '==', platformId).where('shopId', '==', shopId).get()
    if ref:
        return ref[0]
    return None

def updateUserOrders(params):
    from functions.Shipstation.Orders import \
        updateShopOrders as updateUserShipstationOrders
    from functions.Shopify.Orders import \
        updateShopOrders as updateUserShopifyOrders
    from functions.Square.Orders import \
        updateShopOrders as updateuserSquareOrders
    from functions.WooCommerce.Orders import \
        updateShopOrders as updateUserWoocommerceOrders
    from V2.functions.Bigcartel.Orders import \
        updateShopOrders as updateUserBigcartelOrders
    from V2.functions.Etsy.Orders import \
        updateShopOrders as updateUserEtsyOrders
    from V2.functions.Orderdesk.Orders import \
        updateShopOrders as updateUserOrderDeskOrders
    from V2.functions.Squarespace.Orders import \
        updateShopOrders as updateUserSquarespaceOrders
    uid = params.get('currentUser').get('uid')
    shops = getUserShops(uid, credentials=True)
    etsy = [updateUserEtsyOrders(Shop.from_dict(shop)) for shop in shops if shop.get('platformId') == "1"]
    shopify = [updateUserShopifyOrders(shop) for shop in shops if shop.get('platformId') == "2"]
    woo =  [updateUserWoocommerceOrders(shop) for shop in shops if shop.get('platformId') == "3"]
    square = [updateuserSquareOrders(shop) for shop in shops if shop.get("platformId") == "4"]
    shipstation = [updateUserShipstationOrders(shop) for shop in shops if shop.get("platformId") == "5"]
    squarespace = [updateUserSquarespaceOrders(Shop.from_dict(shop)) for shop in shops if shop.get('platformId') == "10"]
    bigcartel = [updateUserBigcartelOrders(Shop.from_dict(shop)) for shop in shops if shop.get("platformId") == "8"]
    orderdesk = [updateUserOrderDeskOrders(Shop.from_dict(shop)) for shop in shops if shop.get("platformId") == "12"]
    res =  dict(
        etsy=etsy,
        shopify=shopify,
        woo=woo, 
        square=square, 
        shipstation=shipstation, 
        squarespace=squarespace,
        bigcartel=bigcartel, 
        orderdesk=orderdesk
        )
    return res

def getOrder(orderId:str):
    ref = db.collection('orders').document(orderId).get()
    if ref.exists:
        return ref.to_dict()
    return {}


def orderMarkShipped(orderId:str, routedOrderId=None):
    ref = db.collection('orders').document(orderId).get()
    if routedOrderId:
        routedRef = db.collection('orders').document(routedOrderId).get()
        if routedRef.exists:
            orderItems = db.collection('orderItems').where('orderId', '==', routedOrderId).get()
            for orderItem in orderItems:
                orderItem.reference.update(dict(
                    shipped=True,
                    shippedAt = SERVER_TIMESTAMP
                ))
            routedRef.reference.update(dict(
                statusTags = ["shipped"],
                shipped=True,
                shippedAt = SERVER_TIMESTAMP
            ))
    if ref.exists:
        orderItems = db.collection('orderItems').where('orderId', '==', orderId).get()
        for orderItem in orderItems:
            orderItem.reference.update(dict(
                shipped=True,
                shippedAt = SERVER_TIMESTAMP
            ))
        ref.reference.update(dict(
            statusTags = ["shipped"],
            shipped=True,
            shippedAt = SERVER_TIMESTAMP
        ))
        return 
    raise API_Error("Order not found.", 404)

def convertImages(
        uid,
        enterpriseId,
        url,
        type='printing',
        placement = '1',
        name = 'CUSTOM'
):
    return dict(
        id=str(datetime.now().timestamp()),
        uid=uid,
        enterpriseId=enterpriseId,
        url=url,
        type=type,
        # createdAt=SERVER_TIMESTAMP,
        placement=placement,
        name=name
    )
