from traceback import print_tb
from rest_framework.exceptions import ValidationError
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import LoadPointMaster,IncoTerms,LoadingSlots,TransportDistanceMaster,TransportMaster,TermsAndConditions,TransporterContacts,ShippingPortMaster,ShippingAgencyMaster
from .serializers import LoadPointMasterSerializer,IncoTermsSerializer,TransportDistanceMasterSerializer,TransportMasterSerializer,TermsAndConditionsSerializer
from django.db import connection
from . import  models as delivery_models
from . import fetch_data

from django.conf import settings
import requests
import os
from django.db.models import Q

from .scripts import sync_transport_data
from django.db.models.functions import Lower

 #class LoadPointMasterListView(APIView):
#     def post(self, request):
#         # Extract LoadPointMasterID from request data (POST body)
#         loadpoint_master_id = request.data.get('loadpoint_id')

#         # If LoadPointMasterID is provided, fetch that specific record
#         if loadpoint_master_id:
#             try:
#                 loadpoint_master = LoadPointMaster.objects.get(LoadPointMasterID=loadpoint_master_id, IsDeleted=False)
#                 serializer = LoadPointMasterSerializer(loadpoint_master)
#                 loading_slots = LoadingSlots.objects.filter(LoadPointId=loadpoint_master_id, IsDeleted=False).values('Id','Slot','TimeFrom','TimeTo')
#                 slots_data = [
#                     {
#                         "Id": slot['Id'],
#                         "Name": slot['Slot'],
#                         "TimeFrom": slot['TimeFrom'],
#                         "TimeTo": slot['TimeTo']
#                     }
#                     for slot in loading_slots
#                 ]
#                 response_data = {
#                     "status_code": 200,
#                     "status": "success",
#                     "message": "LoadPointMaster details fetched successfully",
#                     "data": {
#                         "loadpoint_details": serializer.data,
#                         "loading_slots": slots_data
#                     }
#                 }
#                 return Response(response_data, status=status.HTTP_200_OK)
#             except LoadPointMaster.DoesNotExist:
#                 response_data = {
#                     "status_code": 404,
#                     "status": "error",
#                     "message": "LoadPointMaster not found",
#                     "data": None
#                 }
#                 return Response(response_data, status=status.HTTP_404_NOT_FOUND)

#         # If LoadPointMasterID is not provided, fetch all records
#         loadpoint_masters = LoadPointMaster.objects.filter(IsDeleted=False)
#         serializer = LoadPointMasterSerializer(loadpoint_masters, many=True)
#         response_data = {
#             "status_code": 200,
#             "status": "success",
#             "message": "LoadPointMaster data fetched successfully",
#             "data": serializer.data
#         }
#         return Response(response_data, status=status.HTTP_200_OK)


class LoadPointMasterListView(APIView):
    def post(self, request):
        # Extract LoadPointMasterID from request data (POST body)
        loadpoint_master_id = request.data.get('loadpoint_id')
        loading_slot_id = request.data.get('loading_slot_id')
        # If LoadPointMasterID is provided, fetch that specific record
        if loadpoint_master_id:
            try:
                loadpoint_master = LoadPointMaster.objects.get(LoadPointMasterID=loadpoint_master_id, IsDeleted=False)
                serializer = LoadPointMasterSerializer(loadpoint_master)
                loading_slots = LoadingSlots.objects.filter(LoadPointId=loadpoint_master_id, IsDeleted=False).values('Id','Slot','TimeFrom','TimeTo')
                slots_data = [
                    {
                        "Id": slot['Id'],
                        "Name": slot['Slot'],
                        "TimeFrom": slot['TimeFrom'],
                        "TimeTo": slot['TimeTo']
                    }
                    for slot in loading_slots
                ]
                response_data = {
                    "status_code": 200,
                    "status": "success",
                    "message": "LoadPointMaster details fetched successfully",
                    "data": {
                        "loadpoint_details": serializer.data,
                        "loading_slots": slots_data
                    }
                }
                return Response(response_data, status=status.HTTP_200_OK)
            except LoadPointMaster.DoesNotExist:
                response_data = {
                    "status_code": 404,
                    "status": "error",
                    "message": "LoadPointMaster not found",
                    "data": None
                }
                return Response(response_data, status=status.HTTP_404_NOT_FOUND)
        elif loading_slot_id:
            loading_slots = LoadingSlots.objects.filter(Id=loading_slot_id, IsDeleted=False).values('LoadPointId','Slot','WareHouseCode')
            if loading_slots:
                load_point_master = LoadPointMaster.objects.filter(LoadPointMasterID=loading_slots[0]['LoadPointId']).first()
                slots_data = {
                        "LoadPointId": loading_slots[0]['LoadPointId'],
                        "Name": loading_slots[0]['Slot'],
                        "WareHouseCode": loading_slots[0]['WareHouseCode'],
                        "LoadPointCity":load_point_master.LoadPointCity,
                        "AddressLine1":load_point_master.AddressLine1,
                        "AddressLine2": load_point_master.AddressLine2,
                    }
                response_data = {
                    "status_code": 200,
                    "status": "success",
                    "message": "Loading slot details fetched successfully",
                    "data": slots_data
                }
                return Response(response_data, status=status.HTTP_200_OK)
            else:
                response_data = {
                    "status_code": 404,
                    "status": "error",
                    "message": "Loadingslot details not found",
                    "data": None
                }
                return Response(response_data, status=status.HTTP_404_NOT_FOUND)
        # If LoadPointMasterID is not provided, fetch all records
        loadpoint_masters = LoadPointMaster.objects.filter(IsDeleted=False)
        serializer = LoadPointMasterSerializer(loadpoint_masters, many=True)
        response_data = {
            "status_code": 200,
            "status": "success",
            "message": "LoadPointMaster data fetched successfully",
            "data": serializer.data
        }
        return Response(response_data, status=status.HTTP_200_OK)

class LoadPointForProductView(APIView):
    def post(self, request):
        # Get parameters from the request
        product_id =  request.data.get('product_id')
        load_point_id =  request.data.get('load_point_id')

        if not product_id or not load_point_id:
            return Response(
                {"message": "ProductID and LoadPointID are required"},
                status=status.HTTP_400_BAD_REQUEST
            )
        product_details = get_product_details(request.headers.get('x-auth-token'), product_id)
        # Query
        results = LoadingSlots.objects.filter(
            ProductCategory__icontains=product_details['category'],  # Equivalent to LIKE '%value%'
            IsDeleted=False,
            LoadPointId=load_point_id
        ).values("Id", "Slot", "LoadPointId")

        # Prepare the response data
        # data = [{"Id": result[0], "Slot": result[1], "LoadPointId": result[2]} for result in results]
        return Response({
            "status": "success",
            "status_code": status.HTTP_200_OK,
            "message": "Data fetched successfully",
            "data": results
        }, status=status.HTTP_200_OK)

class IncoTermsListView(APIView):
    def post(self, request):
        # Extract id from the request body
        inco_term_id = request.data.get('id', None)

        # If an ID is provided, fetch the particular IncoTerm
        if inco_term_id:
            try:
                inco_term = IncoTerms.objects.get(Id=inco_term_id, IsDeleted=False)
                serializer = IncoTermsSerializer(inco_term)
                return Response({
                    "status_code": 200,
                    "status": "success",
                    "message": "IncoTerm fetched successfully",
                    "data": serializer.data
                }, status=status.HTTP_200_OK)
            except IncoTerms.DoesNotExist:
                return Response({
                    "status_code": 404,
                    "status": "error",
                    "message": "IncoTerm not found",
                    "data": {}
                }, status=status.HTTP_404_NOT_FOUND)

        # If no ID is provided, fetch all IncoTerms
        else:
            inco_terms = IncoTerms.objects.filter(IsDeleted=False).order_by('SortId')
            serializer = IncoTermsSerializer(inco_terms, many=True)
            return Response({
                "status_code": 200,
                "status": "success",
                "message": "IncoTerms fetched successfully",
                "data": serializer.data
            }, status=status.HTTP_200_OK)

def get_address_city_from_id(auth_token,address_id):     #fetch if any preferred time is there for customer's delivery address
    address_api = settings.CUSTOMER_API_URL+"customers/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"address_id":address_id}
    try:
        response = requests.post(address_api, json=payload,headers=headers)
        if response.status_code == 200:
            address_data = response.json()
            if address_data["data"].get("City"):
               return address_data["data"].get("City")
            else:
                return ""
        else:
            print(f" address  API returned an error: {response.status_code} - {response.text}")
            return []
    except requests.RequestException as e:
        print(f"Error fetching address data: {e}")
        return []

def get_address_city_mapping(auth_token,address_id):     #fetch if any preferred time is there for customer's delivery address
    address_api = settings.CUSTOMER_API_URL+"customers/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"address_id":address_id}
    try:
        response = requests.post(address_api, json=payload,headers=headers)
        if response.status_code == 200:
            address_data = response.json()
            if address_data["data"].get("CityMapping"):
               return address_data["data"].get("CityMapping")
            else:
                return ""
        else:
            print(f" address  API returned an error: {response.status_code} - {response.text}")
            return []
    except requests.RequestException as e:
        print(f"Error fetching address data: {e}")
        return []

def get_product_details(auth_token, product_id):
    api_url = settings.PRODUCT_API_URL + "products/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"product_id": product_id}
    try:
        response = requests.post(api_url, json=payload, headers=headers)

        if response.status_code == 200:
            data = response.json()
            product_details = {
                "name": data.get('data', {}).get('ChemicalName', None),
                "dilution": data.get('data', {}).get('Dilution', None),
                "grade":data.get('data', {}).get('Grade', None),
                "category":data.get('data', {}).get('ProductCategory', None),
                "article_code":data.get('data', {}).get('ArticleCode', None),
                "packaging":data.get('data', {}).get('Packaging', None),
            }
            return product_details
        else:
            return None
    except requests.RequestException as e:
        # Handle exceptions, such as connection errors
        return None

# class TransportPriceApiView(APIView):
#     def post(self, request, *args, **kwargs):
#         product_id = request.data.get('product_id')
#         load_point_id = request.data.get('load_point_id')
#         delivery_address_id = request.data.get('delivery_address_id')
#         packaging_type = request.data.get('packaging_type')
#         inco_term_id = request.data.get('inco_term_id')
#         if not all([product_id, load_point_id, delivery_address_id, packaging_type, inco_term_id]):
#             return Response({
#                 'status': 'error',
#                 'status_code': 400,
#                 'message': 'All required fields are not provided.'
#             }, status=status.HTTP_400_BAD_REQUEST)
#         destination_city = get_address_city_from_id(request.headers.get('x-auth-token'),delivery_address_id)
#         product_details = get_product_details(request.headers.get('x-auth-token'),product_id)
#         load_point_details = LoadPointMaster.objects.values('LoadPointCity').get(LoadPointMasterID=load_point_id)
#         query = """
#                 SELECT tp.Id as PriceId, t.Id, t.Transporter, tp.EffectivePrice
#                 FROM TransportMaster t
#                 JOIN TransportPriceMaster tp ON t.Id = tp.TransporterId
#                 WHERE tp.ChemicalName = %s
#                 AND tp.DilutionFrom <= %s
#                 AND %s <= tp.DilutionTo
#                 AND tp.OriginCity = %s
#                 AND tp.DestinationCity = %s
#                 AND tp.Packaging = %s
#                 AND tp.IncoTermId = %s
#                 ORDER BY tp.EffectivePrice ASC
#         """
#         # Execute the raw SQL query using the `connection` object
#         with connection.cursor() as cursor:
#             cursor.execute(query, [
#                 product_details['name'],
#                 product_details['dilution'],
#                 product_details['dilution'],
#                 load_point_details['LoadPointCity'],
#                 destination_city,
#                 packaging_type,
#                 inco_term_id
#             ])
#             result = cursor.fetchall()  # Fetch all results
#         # Format the result into a dictionary
#         result_list = []
#         for row in result:
#             result_dict = {
#                 'PriceId': row[0],
#                 'TransporterId': row[1],
#                 'Transporter': row[2],
#                 'TransportingPrice': row[3]
#             }
#             result_list.append(result_dict)

#         # Return the response with the fetched data
#         return Response({
#             'status': 'success',
#             'status_code': 200,
#             'message': 'Data fetched successfully',
#             'data': result_list
#         }, status=status.HTTP_200_OK)

def convert_to_number(price_str):
    """
    This function converts a string price with commas and points to a float.
    It replaces commas with points and ensures the string can be converted to a number.

    :param price_str: The price string to convert.
    :return: The numeric value (float) of the price, or 0.0 if conversion fails.
    """
    try:
        # Step 1: Replace commas with points (thousands separator)
        price_str = price_str.replace('.', '')

        # Step 2: Replace the decimal point with a period if necessary
        price_str = price_str.replace(',', '.')

        # Step 3: Convert to float
        return float(price_str)

    except ValueError:
        print("Error: Invalid price format.")
        return 0.0  # Return 0.0 if the conversion fails


def convert_to_belgium_format(price):
    try:
        price_str = str(price)
        price_str = price_str.replace('.', ',')
        return price_str
    except ValueError:
        print("Error: Invalid price format.")
        return 0.0  # Return 0.0 if the conversion fails


class TransportPriceApiView(APIView):
    def post(self, request, *args, **kwargs):
        product_id = request.data.get('product_id')
        load_point_id = request.data.get('load_point_id')
        delivery_address_id = request.data.get('delivery_address_id')
        packaging_type = request.data.get('packaging_type')
        inco_term_id = request.data.get('inco_term_id')
        if not all([product_id, load_point_id, delivery_address_id, packaging_type, inco_term_id]):
            return Response({
                'status': 'error',
                'status_code': 400,
                'message': 'All required fields are not provided.'
            }, status=status.HTTP_400_BAD_REQUEST)
        # destination_city = get_address_city_from_id(request.headers.get('x-auth-token'),delivery_address_id)
        # destination_cities = get_address_city_mapping(request.headers.get('x-auth-token'), delivery_address_id)

        address_data = fetch_data.get_address_data(delivery_address_id)
        postal_code = address_data['postal_code']
        product_details = get_product_details(request.headers.get('x-auth-token'),product_id)
        load_point_details = LoadPointMaster.objects.values('LoadPointCity').get(LoadPointMasterID=load_point_id)

        # city_list = [c.strip() for c in destination_cities.split(',')]
        # placeholders = ",".join(["%s"] * len(city_list))


        # Initialize query and parameters based on Grade condition
        if product_details['grade']:
            is_grade_exists = 1
            grade_condition = "AND tp.Grade = %s"
            params = [
                product_details['name'],
                product_details['dilution'],
                product_details['dilution'],
                load_point_details['LoadPointCity'],
                postal_code,
                product_details['grade'],  # Add Grade as a parameter
            ]
        else:
            grade_condition = ""  # with grade empty
            is_grade_exists = 0
            params = [
                product_details['name'],
                product_details['dilution'],
                product_details['dilution'],
                load_point_details['LoadPointCity'],
                postal_code,
            ]
        # params.extend(city_list)
        # SQL query with a placeholder for grade_condition
        query = f"""
            SELECT tp.Id as PriceId, t.Id, t.Transporter, tp.EffectivePrice
            FROM TransportMaster t
            JOIN TransportPriceMaster tp ON t.Id = tp.TransporterId
            WHERE tp.ChemicalName = %s
            AND tp.DilutionFrom <= %s
            AND %s <= tp.DilutionTo
            AND tp.OriginCity = %s
            AND t.IsDeleted = 0
            AND tp.DestinationZIP = %s
            {grade_condition}
            ORDER BY tp.EffectivePrice ASC
        """

        # Update query to include grade condition if needed
        query = query.replace("{grade_condition}", grade_condition)
        # Execute the query
        with connection.cursor() as cursor:
            cursor.execute(query, params)
            result = cursor.fetchall()
        
        # If no result found and Grade was specified, try fetching without grade
        if not result and is_grade_exists:
            grade_condition = "AND (tp.Grade IS NULL OR tp.Grade = '')"  # Match NULL or empty string
            params = [
                product_details['name'],
                product_details['dilution'],
                product_details['dilution'],
                load_point_details['LoadPointCity'],
                postal_code,
            ]
            # params.extend(city_list)
            query = f"""
                SELECT tp.Id as PriceId, t.Id, t.Transporter, tp.EffectivePrice
                FROM TransportMaster t
                JOIN TransportPriceMaster tp ON t.Id = tp.TransporterId
                WHERE tp.ChemicalName = %s
                AND tp.DilutionFrom <= %s
                AND %s <= tp.DilutionTo
                AND tp.OriginCity = %s
                AND t.IsDeleted = 0
                AND tp.DestinationZIP = %s
                ORDER BY tp.EffectivePrice ASC
            """
            # Replace grade_condition dynamically in the query

            # Execute the query
            with connection.cursor() as cursor:
                cursor.execute(query, params)
                result = cursor.fetchall()
        # Format the result into a dictionary
        result_list = []
        for row in result:
            result_dict = {
                'PriceId': row[0],
                'TransporterId': row[1],
                'Transporter': row[2],
                'TransportingPrice': row[3]
            }
            result_list.append(result_dict)

        # Return the response with the fetched data
        return Response({
            'status': 'success',
            'status_code': 200,
            'message': 'Data fetched successfully',
            'data': result_list
        }, status=status.HTTP_200_OK)

def get_address_code_from_id(auth_token,address_id):     #fetch if any preferred time is there for customer's delivery address
    address_api = settings.CUSTOMER_API_URL+"customers/"
    headers = {
        'x-api-key': os.getenv('API_KEY'),
        'x-content-type': 'application/json',
        'x-auth-token': auth_token,
    }
    payload = {"address_id":address_id}
    try:
        response = requests.post(address_api, json=payload,headers=headers)
        if response.status_code == 200:
            address_data = response.json()
            if address_data["data"].get("ExactERPAddressId"):
               return address_data["data"].get("ExactERPAddressId")
            else:
                return ""
        else:
            print(f" address  API returned an error: {response.status_code} - {response.text}")
            return []
    except requests.RequestException as e:
        print(f"Error fetching address data: {e}")
        return []

class GetTransportTimeView(APIView):
    def post(self, request):
        load_point_id = request.data.get('load_point_id')
        destination_id = request.data.get('destination_id')
        if not load_point_id or not destination_id:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_400_BAD_REQUEST,
                    "message": "LoadPointId and DestinationId are required.",
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        try:
            address_code = get_address_code_from_id(request.headers.get('x-auth-token'), destination_id)
            transport_data = TransportDistanceMaster.objects.filter(
                LoadPointId=load_point_id,
                ExactERPAddressId=address_code,
                IsDeleted=False
            ).first()  # Fetch the first matching record

            if transport_data:
                serializer = TransportDistanceMasterSerializer(transport_data)
                return Response(
                    {
                        "status": "success",
                        "status_code": status.HTTP_200_OK,
                        "message": "Data fetched successfully.",
                        "data": serializer.data,
                    },
                    status=status.HTTP_200_OK
                )
            else:
                return Response(
                    {
                        "status": "error",
                        "status_code": status.HTTP_404_NOT_FOUND,
                        "message": "No data found for the given LoadPointId and DestinationId.",
                        "data": None,
                    },
                    status=status.HTTP_404_NOT_FOUND
                )
        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "message": "An error occurred while fetching the data.",
                    "error": str(e),
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class GetTransporterView(APIView):
    def post(self, request):
        try:
            transporter_id = request.data.get("transporter_id", None)

            if transporter_id:  # If transporter_id is provided, fetch that specific transporter
                transporter = TransportMaster.objects.filter(ID=transporter_id, IsDeleted=False).first()

                if transporter:
                    serializer = TransportMasterSerializer(transporter)
                    return Response(
                        {
                            "status": "success",
                            "status_code": status.HTTP_200_OK,
                            "message": "Data fetched successfully.",
                            "data": serializer.data,
                        },
                        status=status.HTTP_200_OK
                    )
                else:
                    return Response(
                        {
                            "status": "error",
                            "status_code": status.HTTP_404_NOT_FOUND,
                            "message": f"No transporter found with Id: {transporter_id}",
                            "data": None,
                        },
                        status=status.HTTP_404_NOT_FOUND
                    )

            else:  # If transporter_id is not provided, fetch all transporters
                transporters = TransportMaster.objects.filter(IsDeleted=False)
                if transporters.exists():
                    serializer = TransportMasterSerializer(transporters, many=True)
                    return Response(
                        {
                            "status": "success",
                            "status_code": status.HTTP_200_OK,
                            "message": "Data fetched successfully.",
                            "data": serializer.data,
                        },
                        status=status.HTTP_200_OK
                    )
                else:
                    return Response(
                        {
                            "status": "error",
                            "status_code": status.HTTP_404_NOT_FOUND,
                            "message": "No data found.",
                            "data": None,
                        },
                        status=status.HTTP_404_NOT_FOUND
                    )

        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "message": "An error occurred while fetching the data.",
                    "error": str(e),
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

class TermsAndConditionsPostView(APIView):
    def post(self, request, *args, **kwargs):
        # Extract parameters from the POST request body
        article_code = request.data.get('article_code')
        ship_to_code = request.data.get('ship_to_code')
        inco_term = request.data.get('inco_term')

        # Validate parameters
        if not (article_code and ship_to_code and inco_term):
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_400_BAD_REQUEST,
                    "message": "Please provide 'article_code', 'ship_to_code', and 'inco_term'.",
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        queryset = TermsAndConditions.objects.filter(
            ArticleCode=article_code,
            ShipToCode=ship_to_code,
            IncoTerm=inco_term
        )

        if queryset.exists():
            serializer = TermsAndConditionsSerializer(queryset, many=True)
            return Response(
                {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Data fetched successfully.",
                    "data": {
                        "DriverLanguage": serializer.data[0]['DriverLanguage'],
                        "LoadReferenceNeeded":serializer.data[0]['LoadReferenceNeeded'],
                        "WeighingTicketNeeded":serializer.data[0]['WeighingTicketNeeded'],
                        "COCNeeded":serializer.data[0]['COCNeeded'],
                        "COANeeded":serializer.data[0]['COANeeded'],
                        "SealingReportNeeded":serializer.data[0]['SealingReportNeeded'],
                        "LoadListConditions":serializer.data[0]['LoadListConditions'],
                        "DeliveryCertificateNeeded":serializer.data[0]['DeliveryCertificateNeeded'],
                        "CleaningCertificateNeeded": serializer.data[0]['CleaningCertificateNeeded'],
                        "TankType": serializer.data[0]['TankType']
                    },
                },
                status=status.HTTP_200_OK
            )
        else:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_404_NOT_FOUND,
                    "message": "No data found.",
                    "data": None,
                },
                status=status.HTTP_404_NOT_FOUND
            )
def resolve_transporter_mail_ids(transporter_id, product_category):
    """Return the list of mail ids for one transporter and product category.

    Lifted unchanged out of GetTransporterMailIdsView so the bulk endpoint can
    reuse it. The fallback chain is fiddly - category match, then ABS for
    "NABS & ABS", then "all" - and copying it would let the two drift apart.
    """
    if product_category and "H2SO4" in product_category:
        product_category = 'H2SO4'
    # First, try fetching based on the provided ProductCategory
    contacts = TransporterContacts.objects.filter(
        TransporterId=transporter_id,
        ProductCategory__icontains=product_category  # Case-insensitive partial match
    ).values_list("MailIds", flat=True)
    if not contacts.exists():
        if product_category == 'NABS & ABS':
            contacts = TransporterContacts.objects.filter(
                TransporterId=transporter_id,
                ProductCategory__icontains='ABS'  # Case-insensitive partial match
            ).values_list("MailIds", flat=True)
            if not contacts.exists():                    # If no matching MailIds, fetch all MailIds for the TransporterId
                contacts = TransporterContacts.objects.filter(
                    TransporterId=transporter_id,
                    ProductCategory="all"
                ).values_list("MailIds", flat=True)
        else:
            # If no matching MailIds, fetch all MailIds for the TransporterId
            contacts = TransporterContacts.objects.filter(
                TransporterId=transporter_id,
                ProductCategory="all"
            ).values_list("MailIds", flat=True)
    # Convert comma-separated strings into a proper list of emails
    mail_ids = []
    for mail_list in contacts:
        if not mail_list:
            continue
        mail_ids.extend([email.strip() for email in mail_list.split(",") if email.strip()])
    return mail_ids


class GetTransporterMailIdsView(APIView):
    def post(self, request):
        try:
            transporter_id = request.data.get("transporter_id")
            product_category = request.data.get("product_category")

            if not transporter_id or not product_category:
                return Response(
                    {
                        "status": "error",
                        "status_code": status.HTTP_400_BAD_REQUEST,
                        "message": "transporter_id and product_category are required.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            mail_ids = resolve_transporter_mail_ids(transporter_id, product_category)

            if mail_ids:
                return Response(
                    {
                        "status": "success",
                        "status_code": status.HTTP_200_OK,
                        "message": "Mail IDs fetched successfully.",
                        "data": {
                                    "mail_ids":mail_ids
                                }
                    },
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {
                        "status": "error",
                        "status_code": status.HTTP_404_NOT_FOUND,
                        "message": "No mail IDs found for the given TransporterId.",
                    },
                    status=status.HTTP_404_NOT_FOUND,
                )

        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "message": "An error occurred while fetching the data.",
                    "error": str(e),
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

class ShippingPortListView(APIView):
    """The ports a sea container can be collected from and returned to."""

    def get(self, request):
        try:
            ports = list(
                ShippingPortMaster.objects.filter(IsDeleted=False)
                .values('Id', 'PortName', 'CountryCode')
            )
            return Response(
                {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Shipping ports fetched successfully.",
                    "data": ports,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "message": "An error occurred while fetching the data.",
                    "error": str(e),
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class ShippingAgencyListView(APIView):
    """The agencies handling the sea leg.

    MailIds is split the same way transporter contacts are, so the caller gets a
    list rather than a comma separated string.
    """

    def get(self, request):
        try:
            agencies = []
            for row in ShippingAgencyMaster.objects.filter(IsDeleted=False).values(
                'Id', 'AgencyName', 'MailIds'
            ):
                raw = row.get('MailIds') or ''
                agencies.append({
                    'Id': row['Id'],
                    'AgencyName': row['AgencyName'],
                    'MailIds': [m.strip() for m in raw.split(',') if m.strip()],
                })
            return Response(
                {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Shipping agencies fetched successfully.",
                    "data": agencies,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "message": "An error occurred while fetching the data.",
                    "error": str(e),
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class GetTransporterMailIdsBulkView(APIView):
    """Resolve mail ids for several transporters in one call.

    The transporter availability and price request goes to many carriers at
    once, so asking for them one at a time would mean a round trip per carrier.
    The per-transporter rules are unchanged - this only loops them.
    """

    def post(self, request):
        try:
            transporter_ids = request.data.get("transporter_ids")
            product_category = request.data.get("product_category")

            if not transporter_ids or not product_category:
                return Response(
                    {
                        "status": "error",
                        "status_code": status.HTTP_400_BAD_REQUEST,
                        "message": "transporter_ids and product_category are required.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            if not isinstance(transporter_ids, list):
                return Response(
                    {
                        "status": "error",
                        "status_code": status.HTTP_400_BAD_REQUEST,
                        "message": "transporter_ids must be a list.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            results = {}
            missing = []
            for transporter_id in transporter_ids:
                mail_ids = resolve_transporter_mail_ids(transporter_id, product_category)
                results[str(transporter_id)] = mail_ids
                if not mail_ids:
                    missing.append(transporter_id)

            # A transporter with no contact row is reported rather than dropped
            # silently, so the caller can tell the planner who cannot be reached.
            return Response(
                {
                    "status": "success",
                    "status_code": status.HTTP_200_OK,
                    "message": "Mail IDs fetched successfully.",
                    "data": {
                        "mail_ids_by_transporter": results,
                        "transporters_without_mail_ids": missing,
                    }
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            return Response(
                {
                    "status": "error",
                    "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR,
                    "message": "An error occurred while fetching the data.",
                    "error": str(e),
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class LoadingStationForProductView(APIView):
    def post(self, request):
        # # Get parameters from the request
        # product_id =  request.data.get('product_id')
        # if not product_id :
        #     return Response(
        #         {"message": "ProductID is required"},
        #         status=status.HTTP_400_BAD_REQUEST
        #     )
        # product_details = get_product_details(request.headers.get('x-auth-token'), product_id)
        # # Query
        # results = LoadingSlots.objects.filter(
        #     Q(ProductCategory__icontains=product_details['category']) | Q(ProductCategory__isnull=True),
        #     IsDeleted=False,
        # ).values("Id", "Slot", "LoadPointId")
        # return Response({
        #     "status": "success",
        #     "status_code": status.HTTP_200_OK,
        #     "message": "Data fetched successfully",
        #     "data": results
        # }, status=status.HTTP_200_OK)
        results = LoadingSlots.objects.filter(IsDeleted=False).values(
            "Id", "Slot", "LoadPointId", "RequiredReferenceNumber")
        return Response({
            "status": "success",
            "status_code": status.HTTP_200_OK,
            "message": "Data fetched successfully",
            "data": results
        }, status=status.HTTP_200_OK)

class LoadingStationListView(APIView):
    def post(self, request):
        results = LoadingSlots.objects.filter(IsDeleted=False).values("Id", "Slot", "LoadPointId")
        return Response({
            "status": "success",
            "status_code": status.HTTP_200_OK,
            "message": "Data fetched successfully",
            "data": results
        }, status=status.HTTP_200_OK)


class GetTransporterFromProductView(APIView):
    def post(self, request, *args, **kwargs):
        product_id = request.data.get('product_id')
        load_point_id = request.data.get('load_point_id')
        delivery_address_id = request.data.get('delivery_address_id')
        packaging_type = request.data.get('packaging_type')

        destination_city = get_address_city_mapping(request.headers.get('x-auth-token'), delivery_address_id)
        product_details = get_product_details(request.headers.get('x-auth-token'), product_id)
        load_point_details = LoadPointMaster.objects.values('LoadPointCity').get(LoadPointMasterID=load_point_id)

        result_list = []
        existing_transporter_ids = []
        recommended_transporter_id = ""

        if product_details['article_code'] == '50000':
            queryset = delivery_models.TransportPriceMaster.objects.select_related('TransporterId').filter(
                    DestinationCity__icontains='Londonderry', IsDeleted=0
            ).order_by('EffectivePrice')
            for transport_price in queryset:
                result_dict = {
                    'TransporterId': transport_price.TransporterId.ID,
                    'Transporter': f"{transport_price.TransporterId.Transporter} {transport_price.RouteVia}",
                    'TransportingPrice': transport_price.EffectivePrice,
                    'Frequency': transport_price.Frequency
                }
                # if recommended_transporter_id == "":
                #     recommended_transporter_id = transport_price.TransporterId.ID
                existing_transporter_ids.append(transport_price.TransporterId.ID)
                result_list.append(result_dict)
        else:
            result_list = []
            existing_transporter_ids = []
            recommended_transporter_id = ""

            destination_city = destination_city.split(',')
            destination_city = [x.lower().strip() for x in destination_city if x.strip()]

            if product_details['dilution']:

                primary_queryset = delivery_models.TransportPriceMaster.objects.select_related(
                    'TransporterId').annotate(dest_city_lower=Lower('DestinationCity')).filter(
                    ChemicalName=product_details['name'],
                    DilutionFrom__lte=float(product_details['dilution']),
                    DilutionTo__gte=float(product_details['dilution']),
                    OriginCity=load_point_details['LoadPointCity'],
                    dest_city_lower__in=destination_city,
                    Packaging=packaging_type,
                    TransporterId__IsDeleted=False,
                    IsDeleted=False
                ).order_by('EffectivePrice')

                if product_details['grade']:
                    grade = product_details['grade']
                    queryset = primary_queryset.filter(Grade=grade).order_by('EffectivePrice')
                    if not queryset.exists():
                        queryset = primary_queryset.exclude(~Q(Grade__isnull=True) & ~Q(Grade=''))
                else:
                    queryset = primary_queryset.filter(Q(Grade__isnull=True) | Q(Grade='')).order_by('EffectivePrice')

                if not queryset.exists():
                    queryset = primary_queryset

                for transport_price in queryset:
                    result_dict = {
                        'TransporterId': transport_price.TransporterId.ID,
                        'Transporter': transport_price.TransporterId.Transporter,
                        'TransportingPrice': transport_price.EffectivePrice,
                        'Frequency': transport_price.Frequency
                    }
                    if recommended_transporter_id == "":
                        recommended_transporter_id = transport_price.TransporterId.ID
                    existing_transporter_ids.append(transport_price.TransporterId.ID)
                    result_list.append(result_dict)


            if existing_transporter_ids:
                remaining_transporters = TransportMaster.objects.filter(
                    ~Q(ID__in=existing_transporter_ids),
                    IsDeleted=0
                ).values('ID', 'Transporter')
                # Step 3: Add extra transporters with empty TransportingPrice
                for row in remaining_transporters:
                    result_dict = {
                        'TransporterId': row['ID'],
                        'Transporter': row['Transporter'],
                        'TransportingPrice': '',
                        'Frequency': ''
                    }

                    result_list.append(result_dict)
            else:
                remaining_transporters = TransportMaster.objects.filter(
                    IsDeleted=0
                ).values('ID', 'Transporter')
                result_list = []
                for row in remaining_transporters:
                    result_dict = {
                        'TransporterId': row['ID'],
                        'Transporter': row['Transporter'],
                        'TransportingPrice': '',
                        'Frequency': ''
                    }
                    result_list.append(result_dict)

        final_result = {
            "recommended_transporter_id": recommended_transporter_id,
            "list": result_list
        }
        # Return the response with the fetched data
        return Response({
            'status': 'success',
            'status_code': 200,
            'message': 'Data fetched successfully',
            'data': final_result
        }, status=status.HTTP_200_OK)


class TransporterFromProductView(APIView):
    def post(self, request, *args, **kwargs):
        product_id = request.data.get('product_id')
        load_point_id = request.data.get('load_point_id')
        delivery_address_id = request.data.get('delivery_address_id')
        packaging_type = request.data.get('packaging_type')

        destination_city = get_address_city_mapping(request.headers.get('x-auth-token'), delivery_address_id)
        product_details = get_product_details(request.headers.get('x-auth-token'), product_id)
        load_point_details = LoadPointMaster.objects.values('LoadPointCity').get(LoadPointMasterID=load_point_id)

        result_list = []
        existing_transporter_ids = []
        recommended_transporter_id = ""

        if product_details['article_code'] == '50000':
            queryset = delivery_models.TransportPriceMaster.objects.select_related('TransporterId').filter(
                    DestinationCity__icontains='Londonderry', IsDeleted=0
            ).order_by('EffectivePrice')
            for transport_price in queryset:
                result_dict = {
                    'TransporterId': transport_price.TransporterId.ID,
                    'Transporter': f"{transport_price.TransporterId.Transporter} {transport_price.RouteVia}",
                    'TransportingPrice': transport_price.EffectivePrice
                }
                # if recommended_transporter_id == "":
                #     recommended_transporter_id = transport_price.TransporterId.ID
                existing_transporter_ids.append(transport_price.TransporterId.ID)
                result_list.append(result_dict)
        else:
            destination_city = destination_city.split(',')
            primary_queryset = delivery_models.TransportPriceMaster.objects.select_related('TransporterId').filter(
                ChemicalName=product_details['name'],
                DilutionFrom__lte=float(product_details['dilution']),
                DilutionTo__gte=float(product_details['dilution']),
                OriginCity=load_point_details['LoadPointCity'],
                DestinationCity__in=destination_city,
                Packaging=packaging_type,
                TransporterId__IsDeleted=False,
                IsDeleted=False
            ).order_by('EffectivePrice')

            if product_details['grade']:
                grade = product_details['grade']
                queryset = primary_queryset.filter(Grade=grade).order_by('EffectivePrice')
                if not queryset.exists():
                    queryset = primary_queryset.exclude(~Q(Grade__isnull=True) & ~Q(Grade=''))
            else:
                queryset = primary_queryset.filter(Q(Grade__isnull=True) | Q(Grade='')).order_by('EffectivePrice')

            if not queryset.exists():
                queryset = primary_queryset

            result_list = []
            existing_transporter_ids = []
            recommended_transporter_id = ""
            for transport_price in queryset:
                result_dict = {
                    'TransporterId': transport_price.TransporterId.ID,
                    'Transporter': transport_price.TransporterId.Transporter,
                    'TransportingPrice': transport_price.EffectivePrice
                }
                if recommended_transporter_id == "":
                    recommended_transporter_id = transport_price.TransporterId.ID
                existing_transporter_ids.append(transport_price.TransporterId.ID)
                result_list.append(result_dict)
            if existing_transporter_ids:
                remaining_transporters = TransportMaster.objects.filter(
                    ~Q(ID__in=existing_transporter_ids),
                    IsDeleted=0
                ).values('ID', 'Transporter')
                # Step 3: Add extra transporters with empty TransportingPrice
                for row in remaining_transporters:
                    result_dict = {
                        'TransporterId': row['ID'],
                        'Transporter': row['Transporter'],
                        'TransportingPrice': ''
                    }

                    result_list.append(result_dict)
            else:
                remaining_transporters = TransportMaster.objects.filter(
                    IsDeleted=0
                ).values('ID', 'Transporter')
                result_list = []
                for row in remaining_transporters:
                    result_dict = {
                        'TransporterId': row['ID'],
                        'Transporter': row['Transporter'],
                        'TransportingPrice': ''
                    }
                    result_list.append(result_dict)

        final_result = {
            "recommended_transporter_id": recommended_transporter_id,
            "list": result_list
        }
        # Return the response with the fetched data
        return Response({
            'status': 'success',
            'status_code': 200,
            'message': 'Data fetched successfully',
            'data': final_result
        }, status=status.HTTP_200_OK)


class SyncTransportPriceMasterView(APIView):
    def post(self, request, *args, **kwargs):
        """function to sync price data from google sheet"""

        add_data = request.data.get('add_data')
        skip = request.data.get('skip')
        print(request.data.keys())
        if not "add_data" in request.data.keys():
            raise ValidationError({
                "status_code": 400,
                "status": "error",
                "message": "The 'add_data' key is required to sync data with the database. Set it to true to update data, or false to view only.",
                "data": None
            })

        data_not_found, changed_price, skip_list = sync_transport_data.sync_transport_price(add_data, skip)


        return Response(
                {
                    "status_code": 200,
                    "status": "success",
                    "message": "Datas added successfully.",
                    "data_to_add": len(data_not_found),
                    "data_to_update_price": len(changed_price),
                    "data_skiped": len(skip_list),
                    "new_data": data_not_found,
                    "modified_data": changed_price,
                    "skipped_data": skip_list,
                },
                status=status.HTTP_200_OK
            )
