from datetime import datetime

import requests

from functions.LastUpdated import ordersLastUpdated, saveOrdersLastUpdated
from functions.ManualOrders.CsvOrders import findBlankVariantByGtin
from functions.Orders import (convertOrder, convertOrderItem,
                              convertShippingAddress, deleteOrder, saveOrder)
from functions.Products import convertProperty
from functions.Response import API_Error
from functions.Shops import getShopById, getShops, updateShop
from functions.Suppliers.BlankProducts import worker
from functions.WooCommerce import Auth
from V2.functions.Shops.main import Shop


def updateAllOrders(params={}):
    shops = [shop for shop in getShops(platformId="3", credentials= True) if not shop.get("disabled")]
    worker(updateShopOrders, shops)

def updateShopOrders(shop):
    if shop:
            shopId = shop.get('id')
            updates = []
            uid = shop.get('uid')
            enterpriseId = shop.get('enterpriseId')
            consumerKey = shop.get("consumerKey")
            consumerSecret = shop.get("consumerSecret")
            if not (consumerKey or consumerSecret): return
            url = shop.get('url')
            lastUpdate = ordersLastUpdated(shopId)
            failCount = lastUpdate.get("failCount", 0)
            timestamp = int(lastUpdate.get("timestamp")) - 86400
            platformId = shop.get("platformId")
            wcapi = Auth.wooAPI(url, consumerKey, consumerSecret)
            orders = []
            try:
                orders = getOrders(wcapi, modified_after=datetime.fromtimestamp(timestamp).isoformat())
            except Exception as e:
                failCount += 1
                if failCount >= 3:
                    updateShop(shopId, disabled=True)
                saveOrdersLastUpdated(shopId=shopId, count=0, failed=True, failCount=failCount)
                print(e)
                return

            deleted_orders_count = 0

            for order in orders:
                order_status = order.get('status')

                # Check if the order status is not "processing" or "completed"
                if order_status not in ["processing", "completed"]:
                    # Use the deleteOrder function to delete unwanted orders
                    deleteOrder(order.get('id'))
                    deleted_orders_count += 1
                    continue

                shippingAddress = order.get('shipping', {})
                orderItems = order.get('line_items', [])
                totalPrice = sum(float(i.get("price")) for i in orderItems)
                totalDiscount = float(order.get("discount_total"))
                totalShipping = float(order.get("shipping_total"))
                totalTax = float(order.get("total_tax"))
                grandTotal = totalPrice + totalShipping + totalTax - totalDiscount

                convertedOrder = convertOrder(
                    uid=uid,
                    platformId=platformId,
                    shopId=shopId,
                    enterpriseId=enterpriseId,
                    shippingAddress=convertShippingAddress(
                        name=f"{shippingAddress.get('first_name')} {shippingAddress.get('last_name')}",
                        address1=shippingAddress.get('address_1'),
                        address2=shippingAddress.get('address_2'),
                        city=shippingAddress.get('city'),
                        state=shippingAddress.get('state'),
                        zip=shippingAddress.get('postcode'),
                        country=shippingAddress.get('country'),
                    ),
                    createdAt=datetime.fromisoformat(order.get('date_created')),
                    updatedAt=datetime.fromisoformat(order.get('date_modified')),
                    grandTotal=grandTotal,
                    platformOrderId=order.get('id'),
                    shipped=order.get('status') == "completed",
                    cancelled=order.get('status') == "cancelled",
                    currencyCode=order.get('currency'),
                    shippingCost=totalShipping,
                    totalDiscount=totalDiscount,
                    totalPrice=totalPrice,
                    totalTax=totalTax,
                    orderNumber=order.get("number"),
                    shopName=shop.get("name")
                )
                convertOrderItems = []
                for item in orderItems:
                    props = formatProps(item.get("meta_data"))
                    print_images_front = next((prop for prop in props if prop.get("name") == "print_images_front"), None)
                    print_images_back = next((prop for prop in props if prop.get("name") == "print_images_back"), None)
                    blank_variant = next((prop for prop in props if prop.get("name") == "blank_variant"), None)
                    if blank_variant:
                        blankProduct,_, variant, variantMapping = findBlankVariantByGtin(enterpriseId, blank_variant.get("value"))
                        if print_images_front:
                            variantMapping['images'].append(dict(
                                url=print_images_front.get("value"),
                                placement="1",
                                name="Front_Print_Image",
                                id="Front_Print_Image"
                            ))
                        if print_images_back:
                            variantMapping['images'].append(dict(
                                url=print_images_back.get("value"),
                                placement="2",
                                name="Back_Print_Image",
                                id="Back_Print_Image"
                            ))
                        convertedOrderItem = convertOrderItem(
                            uid=uid,
                            enterpriseId=enterpriseId,
                            platformId=platformId,
                            platformOrderId=order.get('id'),
                            platformOrderItemId=item.get('id'),
                            platformProductId=item.get('product_id'),
                            quantity=item.get('quantity'),
                            variantId=item.get('variation_id'),
                            createdAt=datetime.fromisoformat(order.get('date_created')),
                            updatedAt=datetime.fromisoformat(order.get('date_modified')),
                            shopId=shopId,
                            name=item.get('name'),
                            shipped=order.get('status') == "completed",
                            cancelled=order.get('status') == "cancelled",
                            price=item.get('price'),
                            total=item.get('total'),
                            tax=item.get("total_tax"),
                            variantProperties=props,
                            variant=variant,
                            variantMapping=variantMapping,
                 ) 
                    else: convertedOrderItem = convertOrderItem(
                        uid=uid,
                        enterpriseId=enterpriseId,
                        platformId=platformId,
                        platformOrderId=order.get('id'),
                        platformOrderItemId=item.get('id'),
                        platformProductId=item.get('product_id'),
                        quantity=item.get('quantity'),
                        variantId=item.get('variation_id'),
                        createdAt=datetime.fromisoformat(order.get('date_created')),
                        updatedAt=datetime.fromisoformat(order.get('date_modified')),
                        shopId=shopId,
                        name=item.get('name'),
                        shipped=order.get('status') == "completed",
                        cancelled=order.get('status') == "cancelled",
                        price=item.get('price'),
                        total=item.get('total'),
                        tax=item.get("total_tax"),
                        variantProperties=props
                 ) 
                    convertOrderItems.append(convertedOrderItem)
                updates.append(saveOrder(convertedOrder, convertOrderItems))

            saveOrdersLastUpdated(shopId=shopId, count=len(updates))
            return f"Updated orders => {len(updates)}, Deleted orders => {deleted_orders_count}"
    return 'No updates'

def formatProps(props):
    formatted = []
    for prop in props:
        if str(prop.get("key")).startswith("_"): 
            if prop.get("key") == "_tmdata":
                try:
                    data = prop.get("value")[0]
                    fields = data.get("tmcp_post_fields")
                    for key, value in fields.items():
                        formatted.append(
                            convertProperty(
                                        name=key,
                                        value=value,
                                        id=key,
                                    )
                        )
                except: pass
            continue
        else:
            formatted.append(
                convertProperty(
                            name=prop.get("key"),
                            value=prop.get("value"),
                            id=prop.get("id"),
                        )
            )
    return formatted

def getOrders(wcapi, limit=100, modified_after =None, page=1):
    try:
        res = wcapi.get("orders", params=dict(per_page=limit,page=page,modified_after=modified_after))
        if res.status_code == 200:
            orders = list(res.json())
            page = 1
            order_statuses = ["processing", "completed"]
            while len(res.json()) == 100:
                res = wcapi.get("orders", params=dict(per_page=limit, page=page,modified_after=modified_after, status=",".join(order_statuses)))
                orders.extend(res.json())
                page+=1
            return orders
        raise API_Error(res.text)
    except Exception as e:
        raise API_Error(str(e))
    
def getOrder(wcapi, orderId):
    try:
        orders = wcapi.get(f"orders/{orderId}")
        if orders.status_code == 200: return orders.json()
        raise API_Error(orders.text)
    except Exception as e:
        print(e)
    return None


def addOrderNote(wcapi, orderId, note):
    data = dict(
        note=note
    )
    return wcapi.post(f"orders/{orderId}/notes", data)

def updateSingleOrder(shop,orderId, readd=False):
    if shop:
        shopId = shop.get('id')
        uid=shop.get('uid')
        enterpriseId = shop.get('enterpriseId')
        consumerKey = shop.get("consumerKey")
        consumerSecret = shop.get("consumerSecret")
        url = shop.get('url')
        platformId = shop.get("platformId")
        wcapi = Auth.wooAPI(url, consumerKey, consumerSecret)
        order = getOrder(wcapi, orderId)
        if not order: return "Order not found"
        shippingAddress = order.get('shipping', {})
        orderItems = order.get('line_items', [])
        totalPrice = sum(float(i.get("price")*int(i.get("quantity"))) for i in orderItems)
        totalDiscount = float(order.get("discount_total"))
        totalShipping = float(order.get("shipping_total"))
        totalTax = float(order.get("total_tax"))
        grandTotal = totalPrice+totalShipping+totalTax-totalDiscount
        convertedOrder = convertOrder(
            uid=uid,
            platformId=platformId,
            shopId=shopId,
            enterpriseId=enterpriseId,
            shippingAddress=convertShippingAddress(
                name= f"{shippingAddress.get('first_name')} {shippingAddress.get('last_name')}",
                address1= shippingAddress.get('address_1'),
                address2= shippingAddress.get('address_2'),
                city= shippingAddress.get('city'),
                state= shippingAddress.get('state'),
                zip= shippingAddress.get('postcode'),
                country= shippingAddress.get('country'),
            ),
            createdAt= datetime.fromisoformat(order.get('date_created')),
            updatedAt= datetime.fromisoformat(order.get('date_modified')),
            grandTotal=grandTotal,
            platformOrderId=order.get('id'),
            shipped=order.get('status') == "completed",
            cancelled=order.get('status') == "cancelled",
            currencyCode=order.get('currency'),
            shippingCost=totalShipping,
            totalDiscount=totalDiscount,
            totalPrice=totalPrice,
            totalTax=totalTax,
            shopName = shop.get("name"),
            orderNumber=order.get("number"),
        )
        orderItems = order.get('line_items', [])
        convertOrderItems = []
        for item in orderItems:
                props = formatProps(item.get("meta_data"))
                print_images_front = next((prop for prop in props if prop.get("name") == "print_images_front"), None)
                print_images_back = next((prop for prop in props if prop.get("name") == "print_images_back"), None)
                blank_variant = next((prop for prop in props if prop.get("name") == "blank_variant"), None)
                do_not_print = next((prop for prop in props if prop.get("name") == "do_not_print"), None)
                if blank_variant:
                    blankProduct, _, variant, variantMapping = findBlankVariantByGtin(enterpriseId, blank_variant.get("value"))
                    if  variantMapping: 
                        if print_images_front:
                            variantMapping['images'].append(dict(
                                url=print_images_front.get("value"),
                                placement="1",
                                name="Front_Print_Image",
                                id="Front_Print_Image"
                            ))
                        if print_images_back:
                            variantMapping['images'].append(dict(
                                url=print_images_back.get("value"),
                                placement="2",
                                name="Back_Print_Image",
                                id="Back_Print_Image"
                            ))
                    productMapping = dict(
                        ignored = bool(do_not_print),
                        decorationType=None,
                    )
                    convertedOrderItem = convertOrderItem(
                        uid=uid,
                        enterpriseId=enterpriseId,
                        platformId=platformId,
                        platformOrderId=order.get('id'),
                        platformOrderItemId=item.get('id'),
                        platformProductId=item.get('product_id'),
                        quantity=item.get('quantity'),
                        variantId=item.get('variation_id'),
                        createdAt=datetime.fromisoformat(order.get('date_created')),
                        updatedAt=datetime.fromisoformat(order.get('date_modified')),
                        shopId=shopId,
                        name=item.get('name'),
                        shipped=order.get('status') == "completed",
                        cancelled=order.get('status') == "cancelled",
                        price=item.get('price'),
                        total=item.get('total'),
                        tax=item.get("total_tax"),
                        variantProperties=props,
                        variant=variant,
                        variantMapping=variantMapping,
                        productMapping=productMapping,
                        ignored=bool(do_not_print)
                ) 
                else: convertedOrderItem = convertOrderItem(
                    uid=uid,
                    enterpriseId=enterpriseId,
                    platformId=platformId,
                    platformOrderId=order.get('id'),
                    platformOrderItemId=item.get('id'),
                    platformProductId=item.get('product_id'),
                    quantity=item.get('quantity'),
                    variantId=item.get('variation_id'),
                    createdAt=datetime.fromisoformat(order.get('date_created')),
                    updatedAt=datetime.fromisoformat(order.get('date_modified')),
                    shopId=shopId,
                    name=item.get('name'),
                    shipped=order.get('status') == "completed",
                    cancelled=order.get('status') == "cancelled",
                    price=item.get('price'),
                    total=item.get('total'),
                    tax=item.get("total_tax"),
                    variantProperties=props,
                    ignored=bool(do_not_print)
                ) 
                convertOrderItems.append(convertedOrderItem)
        return saveOrder(convertedOrder, convertOrderItems, True, readd)
    return "No shop"

def submitWooShipment(shop:Shop, platformOrderId, carrierName, trackingCode):
    consumerKey = shop.consumerKey
    consumerSecret = shop.consumerSecret
    wcapi = Auth.wooAPI(shop.url, consumerKey, consumerSecret)
    wcapi.put(f"orders/{platformOrderId}", {
        "status":"completed"
    })
    shopurl = str(shop.url).removeprefix("https://").removesuffix("/")
    url = f"https://{shopurl}/wp-json/wc-shipment-tracking/v3/orders/{platformOrderId}/shipment-trackings"
    data ={
      "custom_tracking_provider": carrierName,
      "custom_tracking_link": f"https://aftership.com/{trackingCode}",
      "tracking_number": trackingCode
    }
    addOrderNote(wcapi, platformOrderId, f"{carrierName} Tracking No: {trackingCode}")
    res = requests.post(
        url,
        json=data,
        headers={
            "Content-Type": "application/json",
        },
        auth=(consumerKey, consumerSecret)
    )
    if res.status_code in [200,201]:
        return res.json()
    return False
