import json
from datetime import datetime

import requests

from configs.env import PROJECT_ID
from configs.firebase import db
from functions.Applications import getAppCredentials
from functions.Enterprises import getEnterpriseById
from functions.Response import API_Error, priorityLogger
from functions.Shopify.Auth import apiVersion, createHeader
# from functions.Shopify.Orders import getAssignedOrders
from functions.Shops import getShopById
from V2.functions.Shops.Auth import PLANS
from V2.functions.Shops.main import Shop


def createFulfillmentService(data):
    shopId = data.get('shopId')
    currentUser = data.get('currentUser')
    shop = data.get('shop')
    uid, enterpriseId = currentUser.get('uid'), currentUser.get('enterpriseId')
    enterprise = getEnterpriseById(enterpriseId)
    name = enterprise.get('name', "POD")
    planId = enterprise.get("planId")
    app = getAppCredentials("2"+enterpriseId if planId not in PLANS else "2zNAlxdaZG6hKf6vexv6ljqHyP8i1")
    fulfillmentService = getFulfillmentService(shopId)
    if fulfillmentService: return fulfillmentService
    if not shop: shop = getShopById(shopId, True)
    service = dict(
        name=f'{str(name)} - Fulfillment Service {int(datetime.now().timestamp())}',
        inventory_management=False,
        tracking_support=True,
        callback_url=f"https://riverr-enterprise-integrations-dot-{PROJECT_ID}.uc.r.appspot.com/shopify/fulfillment",
        requires_shipping_method=True,
        format='json',
        fulfillment_orders_opt_in=True,
        location = dict(
            address1= app.get("address1"),
            address2= app.get("address2"),
            city= app.get("city"),
            zip= app.get('zip'),
            country_code = app.get("country_code"),
            name= name
        ) if app else None
    )
    headers = createHeader(shop.get('accessToken'))
    headers['Content-Type'] = 'application/json'
    url = f'{shop.get("url")}/admin/api/{apiVersion}/fulfillment_services.json'
    res = requests.post(url, data=json.dumps(dict(fulfillment_service = service)),json=json.dumps(dict(fulfillment_service = service)), headers=headers)
    if res.status_code == 201:
        fulfillmentService = res.json().get('fulfillment_service')
        db.collection("fulfillmentServices").document(shopId).set(fulfillmentService)
        return fulfillmentService
    raise API_Error(res.text, res.status_code, res.json())

def getFulfillmentService(shopId):
    ref = db.collection("fulfillmentServices").document(shopId).get()
    if ref.exists: return ref.to_dict()
    return None

def getFulfillmentServices(url, headers):
    url = f"{url}/admin/api/{apiVersion}/fulfillment_services.json?scope=current_client"
    res = requests.get(url, headers=headers)
    if res.ok: return res.json().get("fulfillment_services")
    return []

def connectionInventoryLocation(url, headers, itemId, locationId):
    url = f'{url}/admin/api/{apiVersion}/inventory_levels/connect.json'
    data = dict(location_id=locationId, inventory_item_id=itemId, relocate_if_necessary=True)
    res = requests.post(url, data=json.dumps(data), headers=headers)
    if res.status_code == 201: return True
    print(res.text, data)
    return False

def addInventory(shop,location_id, itemId, quantity):
    headers = createHeader(shop.get('accessToken'))
    url = f'{shop.get("url")}/admin/api/{apiVersion}/inventory_levels.json'
    data = dict(inventory_item_id=itemId, location_id=location_id, available=quantity)
    res = requests.post(url, json=data, headers=headers)
    if res.status_code == 201:
        return res.json()
    return None

def submitShopifyShipment(shop:Shop, platformOrderId, carrierName, trackingNumber):
    headers = createHeader(shop.accessToken)
    fulfillmentOrders = getFulfillmentOrders(shop.url, headers, platformOrderId)
    fulfillmentOrderId = None
    if len(fulfillmentOrders)>0:
        fulfillmentOrderId = fulfillmentOrders[0].get("id")
    else: 
        priorityLogger(shop.uid, "submitShopifyShipment", f"No fulfillment order found {platformOrderId}")
        print("No fulfillment order found", platformOrderId)
    # "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"
    # fulfillmentService = getFulfillmentService(shop.get('id'))
    # if not fulfillmentService: 
    #     fulfillmentService = createFulfillmentService(dict(shopId=shop.get('id'), currentUser=dict(
    #         uid = shop.get("uid"),
    #         enterpriseId = shop.get("enterpriseId")
    #     ), shop=shop))
    # locationId = fulfillmentService.get('location_id')
    # order = getOrder(s)
    res = requests.post(f"{shop.url}/admin/api/{apiVersion}/fulfillments.json",
        headers=headers,
        json=dict(
            fulfillment=dict(
                tracking_info=dict(
                    number = trackingNumber,
                    company = carrierName
                ),
                notify_customer=True,
                line_items_by_fulfillment_order=[{"fulfillment_order_id":fulfillmentOrderId}],
            )
        )
    )
    if res.status_code == 201:
        print("Shipment submitted to Shopify", platformOrderId)
        return res.json()
    else:
        priorityLogger("None", "submitShopifyShipment", res.text, platformOrderId = platformOrderId, data = res.request.body)
        print(res.text)
        return None
# def sendFulfillmentRequest(url, headers, platformOrderId):
#     res = requests.post(f"{url}/admin/api/2022-07/fulfillment_orders/{platformOrderId}/fulfillment_request.json",
#         headers=headers)
#     print(res.text)
#     if res.status_code == 200:
#         return res.json().get("original_fulfillment_order")
#     return None
def getFulfillmentOrders(url, headers, platformOrderId):
    res = requests.get(f"{url}/admin/api/{apiVersion}/orders/{platformOrderId}/fulfillment_orders.json",
        headers=headers)
    if res.status_code == 200:
        return res.json().get("fulfillment_orders")
    priorityLogger("None", "getFulfillmentOrders", res.text, url=url, headers=headers, platformOrderId=platformOrderId)
    return None

def deleteFulfillmentService(shoId):
    ref = db.collection("fulfillmentServices").document(shoId).get()
    if ref.exists:
        ref.reference.delete()
        return ref.id
    return None


def getFulfillmentLocation(shopId):
    ref = db.document(f"fulfillmentServices/{shopId}").get()
    if ref.exists: return ref.to_dict()

def removeWrongFulfillmentLocations(shopId):
    shop = Shop.get(shopId)
    currentLocation = getFulfillmentLocation(shopId)
    if not currentLocation: return
    currentLocationId = currentLocation.get("id")
    headers = createHeader(shop.accessToken)
    locations = getFulfillmentServices(shop.url, headers=headers)
    locationsToRemove = [l for l in locations if l.get("id") != currentLocationId]
    responses = []
    for locationToRemove in locationsToRemove:
        url = f"{shop.url}/admin/api/2024-04/fulfillment_services/{locationToRemove.get('id')}.json"
        res = requests.delete(url, headers=headers)
        responses.append(res.text)
    return responses


# removeWrongFulfillmentLocations("ThEUfqYypVaq66Lycb3e")


def move_orders_to_fulfillment_location(shopId):
    """
    Use Shopify's GraphQL API to check order shipment status, move fulfillment orders, 
    and submit shipment details if not shipped.
    """
    try:
        # Step 1: Fetch orders and fulfillment location
        orders = db.collection("orders").where("shopId", "==", shopId).get()
        fulfillment_location = getFulfillmentLocation(shopId)
        print("fulfillment_location", fulfillment_location)
        if not orders: print(f"No orders found for shop {shopId}.")
        print("Orders: ", len(orders))
        if not fulfillment_location:
            print(f"No fulfillment location found for shop {shopId}.")
            return
        
        shop = getShopById(shopId, True)
        shop_url = shop.get("url")
        access_token = shop.get("accessToken")
        headers = createHeader(access_token)
        
        for order in orders:
            order_data = order.to_dict()
            platform_order_id = order_data.get("platformOrderId")  # Shopify Order ID


            # Step 2: Check if the order is shipped in Shopify
            graphql_url = f"{shop_url}/admin/api/{apiVersion}/graphql.json"
            print(graphql_url)
            query_order_shipment = f"""
            {{
                order(id: "gid://shopify/Order/{platform_order_id}") {{
                    fulfillmentStatus
                }}
            }}
            """
            response = requests.post(graphql_url, headers=headers, json={"query": query_order_shipment})
            if response.status_code != 200:
                print(f"Failed to fetch shipment status for order {platform_order_id}. Response: {response.text}")
                continue

            shipment_status = response.json().get("data", {}).get("order", {}).get("fulfillmentStatus")
            if shipment_status == "shipped":
                print(f"Order {platform_order_id} is already shipped.")
                continue  # Skip to the next order

            # Step 3: Fetch fulfillment orders
            query_fulfillment_orders = f"""
            {{
                order(id: "gid://shopify/Order/{platform_order_id}") {{
                    fulfillmentOrders {{
                        id
                    }}
                }}
            }}
            """
            response = requests.post(graphql_url, headers=headers, json={"query": query_fulfillment_orders})
            if response.status_code != 200:
                print(f"Failed to fetch fulfillment orders for order {platform_order_id}. Response: {response.text}")
                continue

            fulfillment_orders = response.json().get("data", {}).get("order", {}).get("fulfillmentOrders", [])
            if not fulfillment_orders:
                print(f"No fulfillment orders found for order {platform_order_id}.")
                continue

            fulfillment_order_id = fulfillment_orders[0]["id"]

            # Step 4: Move the fulfillment order
            move_fulfillment_order_mutation = f"""
            mutation {{
                moveFulfillmentOrder(
                    id: "{fulfillment_order_id}",
                    newLocationId: "gid://shopify/Location/{fulfillment_location.get('id')}"
                ) {{
                    movedFulfillmentOrder {{
                        id
                    }}
                    userErrors {{
                        field
                        message
                    }}
                }}
            }}
            """
            move_response = requests.post(graphql_url, headers=headers, json={"query": move_fulfillment_order_mutation})
            if move_response.status_code != 200:
                print(f"Failed to move fulfillment order {fulfillment_order_id}. Response: {move_response.text}")
                continue
            print("Orders moved to fulfillment location", fulfillment_location.get('id'), fulfillment_order_id)
            # Check for errors in move response
            user_errors = move_response.json().get("data", {}).get("moveFulfillmentOrder", {}).get("userErrors", [])
            if user_errors:
                print(f"Errors while moving fulfillment order {fulfillment_order_id}: {user_errors}")
                continue

            print(f"Successfully moved fulfillment order {fulfillment_order_id} to location {fulfillment_location.get('id')}.")

            # Step 5: Fetch shipment details from the database
            shipment = db.collection("shipments").where("orderId", "==", order.id).get()
            if not shipment:
                print(f"No shipment details found for order {order.id}.")
                continue

            shipment_data = shipment[0].to_dict()

            # Step 6: Submit the shipment details
            submit_shipment_mutation = f"""
            mutation {{
                fulfillmentCreateV2(input: {{
                    orderId: "gid://shopify/Order/{platform_order_id}",
                    lineItemsByFulfillmentOrder: [{{
                        fulfillmentOrderId: "{fulfillment_order_id}",
                        fulfillmentLineItems: []
                    }}],
                    trackingInfo: {{
                        number: "{shipment_data.get('trackingNumber')}",
                        company: "{shipment_data.get('carrierName')}"
                    }},
                    locationId: "gid://shopify/Location/{fulfillment_location.get('id')}"
                }}) {{
                    fulfillment {{
                        id
                    }}
                    userErrors {{
                        field
                        message
                    }}
                }}
            }}
            """
            shipment_response = requests.post(graphql_url, headers=headers, json={"query": submit_shipment_mutation})
            if shipment_response.status_code != 200:
                print(f"Failed to submit shipment for order {platform_order_id}. Response: {shipment_response.text}")
                continue

            # Check for errors in shipment response
            user_errors = shipment_response.json().get("data", {}).get("fulfillmentCreateV2", {}).get("userErrors", [])
            if user_errors:
                print(f"Errors while submitting shipment for order {platform_order_id}: {user_errors}")
                continue

            print(f"Successfully submitted shipment for order {platform_order_id}.")

    except Exception as e:
        raise API_Error("Failed to move orders to fulfillment locations.")
    

# move_orders_to_fulfillment_location("ThEUfqYypVaq66Lycb3e")