
import json
from django.conf import settings
import requests
from datetime import datetime, timedelta

from orders.models import Delhivery, DeliveryMatrix
import logging
import pandas as pd

def calculate_cart_weight(cart):
    """
    Calculate total cart weight in grams
    """
    if not cart or not cart.items.exists():
        return 0
        
    total_weight = 0

    for item in cart.items.all():
        sku = item.sku
        
        # Get quantity per unit (pack size)
        quantity = sku.sku_quantity
        unit = sku.sku_unit
        
        # Convert to grams
        weight_per_pack = convert_to_grams(quantity, unit)
        
        # If weight is 0, use default weight of 500g per item
        if weight_per_pack == 0:
            weight_per_pack = 500
        
        # Multiply by number of packs in cart
        total_weight += weight_per_pack * item.quantity
        

    # Add 5% packaging weight
    packaging_weight = total_weight * 0.05
    total_weight += packaging_weight
    

    return int(round(total_weight)) if total_weight > 0 else 500  # Minimum 500g


def convert_to_grams(quantity, unit):
    unit = unit.lower().strip()

    # Weight units
    if unit in ["kg", "kilogram", "kilograms"]:
        return quantity * 1000
    elif unit in ["g", "gram", "grams", "gm", "gms"]:  # ✅ Added "gm" and "gms"
        return quantity
    elif unit in ["mg", "milligram", "milligrams"]:
        return quantity / 1000
    
    # Volume units (assuming 1ml = 1g for food items)
    elif unit in ["l", "liter", "liters"]:
        return quantity * 1000
    elif unit in ["ml", "milliliter", "milliliters"]:
        return quantity
    
    # Count-based items
    elif unit in ["pc", "pcs", "piece", "pieces", "no", "nos", "number", "numbers"]:
        # Assuming each piece is approximately 200g (adjust based on your products)
        return quantity * 200
    
    # Default fallback
    else:
        logging.warning(f"Unknown unit: {unit}, defaulting to 0")
        return 0
    



def get_delivery_info(pincode):
    data = DeliveryMatrix.objects.filter(pincode=pincode).values(
        "tat_surface", "tat_express"
    ).first()

    if not data:
        return {
            "tat_surface": None,
            "tat_express": None
        }

    return {
        "tat_surface": data["tat_surface"] if data["tat_surface"] else None,
        "tat_express": data["tat_express"] if data["tat_express"] else None
    }



def get_pincode_from_latlng(lat, lng):

    url = "https://maps.googleapis.com/maps/api/geocode/json"

    params = {
        "latlng": f"{lat},{lng}",
        "key": settings.GOOGLE_MAPS_API_KEY
    }

    try:
        response = requests.get(url, params=params, timeout=(3, 5))
        response.raise_for_status()

        data = response.json()
        logging.info(f"Google Maps response: {data}")

        if data.get("status") == "OK":
            for result in data.get("results", []):
                for comp in result.get("address_components", []):
                    if "postal_code" in comp.get("types", []):
                        return comp.get("long_name")

    except Exception:
        logging.exception("Google Maps API failed")

    return None



def create_delhivery_shipment(order, payment_type):

    url = "https://staging-express.delhivery.com/api/cmu/create.json"

    # Payment mode
    if payment_type == "COD":
        payment_mode = "COD"
        cod_amount = order.grand_total
    else:
        payment_mode = "Prepaid"
        cod_amount = 0

    # Pickup (warehouse)
    pu = order.pu_uuid

    pickup_name = pu.pu_name  # MUST match Delhivery dashboard EXACTLY

    # Customer address
    address = order.drop_address
    weight_grams =Delhivery.objects.filter(order=order).first().weight_grams            
    shipment_data = {
        "shipments": [
            {
                "name": order.user_uuid.first_name,
                "add": address.house_number_or_name,
                "pin": str(address.pin_code),
                "city": address.city,
                "state": address.state_or_province,
                "country": "India",
                "phone": order.user_uuid.phone_number,

                "order": order.order_ID,

                "payment_mode": payment_mode,
                "cod_amount": str(cod_amount),

                "products_desc": "Bakery Items",
                "quantity": "1",

                "weight": str(weight_grams),

                "shipping_mode": "Surface",

                "fragile_shipment": True,

                "shipment_width": "20",
                "shipment_height": "15",
                "shipment_length": "20",

                # Return address (VERY IMPORTANT)
                "return_name": pu.pu_name,
                "return_add": pu.pu_location,
                "return_city": pu.city,
                "return_state": pu.state_or_province,
                "return_country": "India",
                "return_pin": pu.pin_code,
                "return_phone": pu.contact_no,
            }
        ],
        "pickup_location": {
            "name": pickup_name
        }
    }

    # 🔥 IMPORTANT: Convert to string format required by Delhivery
    payload = "format=json&data=" + json.dumps(shipment_data)

    headers = {
        "Authorization": f"Token {settings.DELHIVERY_API_KEY}",
        "Accept": "application/json",
        "Content-Type": "application/json"
    }

    try:
        response = requests.post(url, data=payload, headers=headers , timeout=5)
        data = response.json()


        # Extract AWB
        packages = data.get("packages", [])

        if packages:
            awb = packages[0].get("waybill")

            tracking_url = f"https://www.delhivery.com/tracking?awb={awb}"

            return {
                "success": True,
                "awb": awb,
                "tracking_url": tracking_url,
                "raw": data
            }

        return {"success": False, "error": data}

    except Exception as e:
        return {"success": False, "error": str(e)}





def get_expected_delivery_time(origin_pin, destination_pin, mode="S"):

    url = "https://track.delhivery.com/api/dc/expected_tat"

    pickup_date = (datetime.today() + timedelta(days=1)).strftime("%Y-%m-%d")

    params = {
        "origin_pin": str(origin_pin),
        "destination_pin": str(destination_pin),
        "mot": mode,
        "pdt": "B2C",
        "expected_pickup_date": pickup_date
    }

    headers = {
        "Accept": "application/json",
        "Authorization": f"Token {settings.DELHIVERY_API_KEY}"
    }

    try:
        response = requests.get(url, params=params, headers=headers, timeout=(3, 5))
        response.raise_for_status()

        data = response.json()
        logging.info(f"TAT API response: {data}")

        if isinstance(data, list):
            data = data[0] if data else {}

        tat = data.get("tat")
        expected_date = data.get("expected_delivery_date")

        if not tat:
            return {"tat": "3-5", "expected_delivery_date": None}

        return {
            "tat": str(tat),
            "expected_delivery_date": expected_date
        }

    except Exception:
        logging.exception("TAT API failed")
        return {"tat": "3-5", "expected_delivery_date": None}

def check_pincode(pincode):
    url = f"https://staging-express.delhivery.com/c/api/pin-codes/json/?filter_codes={pincode}"

    headers = {
        "Authorization": f"Token {settings.DELHIVERY_API_KEY}",
        "Accept": "application/json"
    }

    try:
        response = requests.get(url, headers=headers , timeout=5)

        # If API fails
        if response.status_code != 200:
            return False

        data = response.json()
        delivery_codes = data.get("delivery_codes", [])

        # Return True if serviceable and not embargo
        return bool(
            delivery_codes and
            delivery_codes[0].get("postal_code", {}).get("remark") != "Embargo"
        )

    except:
        return False
    
def get_delhivery_charge(pickup_pin, drop_pin, cart_weight, pt, mode):

    url = "https://staging-express.delhivery.com/api/kinko/v1/invoice/charges/.json"

    params = {
        "md": mode,
        "ss": "Delivered",
        "d_pin": drop_pin,
        "o_pin": pickup_pin,
        "cgm": cart_weight,
        "pt": pt
    }

    try:
        response = requests.get(
            url,
            params=params,
            headers={"Authorization": f"Token {settings.DELHIVERY_API_KEY}"},
            timeout=(3, 5)
        )

        response.raise_for_status()
        data = response.json()

        logging.info(f"Delhivery charge API success | data: {data}")

        if isinstance(data, list):
            return data[0].get("total_amount", 0) if data else 0

        if isinstance(data, dict):
            return data.get("total_amount", 0)

        return 0

    except Exception:
        logging.exception("Delhivery charge API failed")
        return 0


def get_full_address_from_latlng(lat, lng):
    url = "https://maps.googleapis.com/maps/api/geocode/json"

    params = {
        "latlng": f"{lat},{lng}",
        "key": settings.GOOGLE_MAPS_API_KEY
    }

    response = requests.get(url, params=params, timeout=5)
    data = response.json()

    result = {
        "street": None,
        "city": None,
        "state": None,
        "pincode": None
    }

    if data["status"] == "OK":
        for comp in data["results"][0]["address_components"]:
            types = comp["types"]

            if "route" in types:
                result["street"] = comp["long_name"]
            elif "locality" in types:
                result["city"] = comp["long_name"]
            elif "administrative_area_level_1" in types:
                result["state"] = comp["long_name"]
            elif "postal_code" in types:
                result["pincode"] = comp["long_name"]

    return result