from django.core.mail import send_mail
from users.models import Airlines, ClientFrequentFlyer, Countries, UserPermissions, State, Cities
import random
from django.db import models
from django.db.models.fields.files import FieldFile
from datetime import datetime
from django.forms.models import model_to_dict
from django.db.models import FileField
from django.core.serializers.json import DjangoJSONEncoder
import json

def generate_otp():
    return str(random.randint(100000, 999999))

def send_login_otp(email, otp):
    send_mail(
        subject="Your Login OTP - My Value Trip",
        message=f"Your OTP for login is: {otp} \n\n This OTP is valid for 5 minutes.  Please do not share this OTP with anyone else.",
        from_email="info@myvaluetrips.co.in",
        recipient_list=[email],
        fail_silently=False,
    )

def send_forgot_password_otp(email, otp):
    subject = 'Your Password Reset OTP'
    message = f'Use this OTP to reset your password: {otp} \n\n This OTP is valid for 5 minutes.  Please do not share this OTP with anyone else.'
    send_mail(
        subject, message, 'info@myvaluetrips.co.in', [email], fail_silently=False)



def get_assigned_menu(user):
    """Return a safe, recursion-free list of menu dicts for the sidebar."""
    if not user or not user.is_authenticated:
        return []
    return list(
        UserPermissions.objects
        .filter(ref_user=user)  # fixed foreign key name
        .select_related('ref_menu')
        .order_by('ref_menu__menu_order_no')
        .values(
            'ref_menu__id',
            'ref_menu__menu_name',
            'ref_menu__menu_url',
            'ref_menu__icon',
            'ref_menu__menu_order_no'
        )
    )


def get_changed_fields(old_instance, new_instance, exclude_fields=None):
    """
    Compare old_instance and new_instance, return dict of changed fields.
    """
    exclude_fields = exclude_fields or []
    changes = {}

    for field in new_instance._meta.fields:
        field_name = field.name
        if field_name in exclude_fields:
            continue

        old_value = getattr(old_instance, field_name, None)
        new_value = getattr(new_instance, field_name, None)

        if old_value != new_value:
            changes[field_name] = {"old": old_value, "new": new_value}

    return changes


def normalize_client_payload(data):
    """
    Convert incoming payload keys like clientDetails[firstName]
    into serializer-friendly keys like client_first_name
    """

    client_map = {
        "clientDetails[firstName]": "client_first_name",
        "clientDetails[middleName]": "client_middle_name",
        "clientDetails[lastName]": "client_last_name",
        "clientDetails[salutation]": "client_salutation",
        "clientDetails[dob]": "dob",
        "clientDetails[gender]": "gender",
        "clientDetails[occupation]": "occupation",
        "clientDetails[maritalStatus]": "marital_status",
        "clientDetails[reference]": "reference_from",
        "clientDetails[country]": "residential_country",
        "clientDetails[state]": "residential_state",
        "clientDetails[city]": "residential_city",
        "clientDetails[pincode]": "residential_pincode",
        "clientDetails[countryCode]": "country_code",
        "clientDetails[contactNo]": "contact_no",
        "clientDetails[email]": "email",
        "clientDetails[preferredContact]": "preferred_contact_method",
        "clientDetails[residentialAddress]": "residential_address",
        "clientDetails[aadhaarNo]": "aadhaar_no",
        "clientDetails[panNo]": "pan_no",
    }

    normalized = {}
    for key, val in data.items():
        if key in client_map:
            normalized[client_map[key]] = val
        elif key.startswith("companies["):
            # Example: companies[0][company] -> companies -> [{ref_company_id: ...}]
            idx = int(key.split("[")[1].split("]")[0])
            field = key.split("][")[-1].replace("]", "")
            if "companies" not in normalized:
                normalized["companies"] = []
            while len(normalized["companies"]) <= idx:
                normalized["companies"].append({})
            if field == "company":
                normalized["companies"][idx]["ref_company_id"] = val
            elif field == "designation":
                normalized["companies"][idx]["designation"] = val
            elif field == "primary":
                normalized["companies"][idx]["is_primary"] = val.lower() in ["true", "1"]
        else:
            # fallback: keep as-is
            normalized[key] = val

    return normalized


def _find_non_serializables(obj, path="root"):
    import django.db.models.fields.files as filefields
    issues = []

    if isinstance(obj, dict):
        for k, v in obj.items():
            issues += _find_non_serializables(v, f"{path}.{k}")
    elif isinstance(obj, list):
        for i, v in enumerate(obj):
            issues += _find_non_serializables(v, f"{path}[{i}]")
    else:
        try:
            from django.core.files.base import File
            if isinstance(obj, File) or obj.__class__.__name__.endswith("FieldFile"):
                issues.append((path, type(obj).__name__))
        except Exception:
            pass
    return issues


def serialize_instance(instance, exclude_fields=None):
    print(">>> Using SAFE serialize_instance")  # Debug check
    data = {}
    exclude_fields = exclude_fields or []

    for field in instance._meta.fields:
        if field.name in exclude_fields:
            continue

        value = getattr(instance, field.name)

        if isinstance(value, FieldFile):
            # Catch the ValueError instead of letting it crash
            try:
                data[field.name] = value.url if value and value.name else None
            except ValueError:
                data[field.name] = None
        else:
            data[field.name] = value

    return data

# def build_changes(old_data, new_data):
#     """
#     Compare old_data and new_data dictionaries and return a dictionary of changed fields.
#     If old_data is None (e.g., for creation), return new_data as the changes.
#     """
#     changes = {}
    
#     if old_data is None:  # For creation, all fields in new_data are "changes"
#         return new_data
    
#     # Compare fields present in both old_data and new_data
#     for key in new_data:
#         if key in old_data and old_data[key] != new_data[key]:
#             changes[key] = {"old": old_data[key], "new": new_data[key]}
    
#     return changes

# def build_changes(old_data, new_data):
#     """
#     Compare old_data and new_data dictionaries, handling FKs, files, and related fields robustly.
#     Return a dictionary of changed fields.
#     """
#     changes = {}
    
#     if old_data is None:
#         return changes  # No changes if no old data

#     for key in set(old_data.keys()) | set(new_data.keys()):
#         old_value = old_data.get(key)
#         new_value = new_data.get(key)

#         # Handle lists (related fields like client_passport)
#         if isinstance(new_value, list) and isinstance(old_value, list):
#             # Compare lists by serializing each item to JSON to handle nested dictionaries
#             old_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in old_value])
#             new_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in new_value])
#             if old_items != new_items:
#                 changes[key] = {"old": old_value, "new": new_value}
#         # Handle scalars, treating None and "" as equivalent for nullable fields
#         elif old_value != new_value and not (old_value is None and new_value == "") and not (old_value == "" and new_value is None):
#             # Special handling for file fields
#             if isinstance(old_value, str) and isinstance(new_value, str) and 'media/' in old_value:
#                 # Compare file URLs/paths
#                 if old_value != new_value:
#                     changes[key] = {"old": old_value, "new": new_value}
#             else:
#                 changes[key] = {"old": old_value, "new": new_value}
    
#     return changes

# def build_changes(old_data, new_data):
#     """
#     Compare old_data and new_data dictionaries, handling FKs, files, and related fields robustly.
#     Return a dictionary of changed fields.
#     """
#     changes = {}
    
#     if old_data is None:
#         return changes  # No changes if no old data

#     for key in set(old_data.keys()) | set(new_data.keys()):
#         old_value = old_data.get(key)
#         new_value = new_data.get(key)

#         # Handle lists (related fields like client_passport)
#         if isinstance(new_value, list) and isinstance(old_value, list):
#             # Compare lists by serializing each item to JSON to handle nested dictionaries
#             old_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in old_value])
#             new_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in new_value])
#             if old_items != new_items:
#                 changes[key] = {"old": old_value, "new": new_value}
#         # Handle scalars, treating None and "" as equivalent for nullable fields
#         elif old_value != new_value and not (old_value is None and new_value == "") and not (old_value == "" and new_value is None):
#             # Handle file fields explicitly
#             if key in ['aadhaar_card_file', 'pan_card_file'] or 'file' in key.lower() or 'document' in key.lower():
#                 # Compare file fields (None, string, or file object)
#                 old_file = old_value if old_value else None
#                 new_file = new_value if new_value else None
#                 if old_file != new_file:
#                     changes[key] = {"old": old_file, "new": new_file}
#             else:
#                 changes[key] = {"old": old_value, "new": new_value}
    
#     return changes

# def build_changes(old_data, new_data):
#     """
#     Compare old_data and new_data dictionaries, handling FKs, files, and related fields robustly.
#     Return a dictionary of changed fields.
#     """
#     changes = {}
    
#     if old_data is None:
#         return changes  # No changes if no old data

#     for key in set(old_data.keys()) | set(new_data.keys()):
#         old_value = old_data.get(key)
#         new_value = new_data.get(key)

#         # Handle lists (related fields like client_passport)
#         if isinstance(new_value, list) and isinstance(old_value, list):
#             # Compare lists by serializing each item to JSON to handle nested dictionaries
#             old_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in old_value])
#             new_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in new_value])
#             if old_items != new_items:
#                 changes[key] = {"old": old_value, "new": new_value}
#         # Handle scalars, treating None and "" as equivalent for nullable fields
#         elif old_value != new_value and not (old_value is None and new_value == "") and not (old_value == "" and new_value is None):
#             # Handle file fields explicitly
#             if key in ['aadhaar_card_file', 'pan_card_file'] or 'file' in key.lower() or 'document' in key.lower():
#                 # Compare file fields (None, string, or file object)
#                 old_file = old_value if old_value else None
#                 new_file = new_value if new_value else None
#                 if old_file != new_file:
#                     changes[key] = {"old": old_file, "new": new_file}
#             else:
#                 changes[key] = {"old": old_value, "new": new_value}
    
#     return changes

def build_changes(old_data, new_data):
    """
    Compare old_data and new_data dictionaries, handling FKs, files, and related fields robustly.
    Return a dictionary of changed fields in the format {"field": {"old": old_value, "new": new_value}}.
    """
    changes = {}
    
    if old_data is None:
        return changes  # No changes if no old data

    for key in set(old_data.keys()) | set(new_data.keys()):
        old_value = old_data.get(key)
        new_value = new_data.get(key)

        # Handle lists (related fields like client_visa, client_passport)
        if isinstance(new_value, list) and isinstance(old_value, list):
            # Compare lists by serializing to JSON to ensure identical lists are detected
            old_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in old_value])
            new_items = sorted([json.dumps(item, sort_keys=True, cls=DjangoJSONEncoder) for item in new_value])
            if old_items != new_items:
                # For nested lists, log the entire old and new lists to match original format
                changes[key] = {"old": old_value, "new": new_value}
        # Handle scalars, treating None and "" as equivalent for nullable fields
        elif old_value != new_value and not (old_value is None and new_value == "") and not (old_value == "" and new_value is None):
            # Handle file fields explicitly
            if key in ['aadhaar_card_file', 'pan_card_file'] or 'file' in key.lower() or 'document' in key.lower() or 'photograph' in key.lower():
                old_file = old_value if old_value else None
                new_file = new_value if new_value else None
                if old_file != new_file:
                    changes[key] = {"old": old_file, "new": new_file}
            else:
                changes[key] = {"old": old_value, "new": new_value}
    
    return changes

def convert_datetime(obj):
    """Recursively convert datetime/date objects to string in desired format."""
    if isinstance(obj, dict):
        return {k: convert_datetime(v) for k, v in obj.items()}
    elif isinstance(obj, list):
        return [convert_datetime(v) for v in obj]
    elif isinstance(obj, datetime.datetime):
        return obj.strftime("%Y-%m-%d %H:%M:%S")
    elif isinstance(obj, datetime.date):
        return obj.strftime("%Y-%m-%d")   
    return obj


'''
def serialize_instance(instance, exclude_fields=None):
    data = {}
    exclude_fields = exclude_fields or []

    for field in instance._meta.get_fields():
        if field.name in exclude_fields:
            continue

        value = getattr(instance, field.name, None)

        # Handle FileFields safely
        if hasattr(value, "url") or hasattr(value, "path"):
            if value and getattr(value, "name", None):  # file exists
                data[field.name] = value.url
            else:
                data[field.name] = None
        else:
            data[field.name] = str(value) if value is not None else None

    return data
'''

'''
def serialize_instance(instance):
    data = {}
    for field in instance._meta.get_fields():
        if field.many_to_many or field.one_to_many:
            continue
        field_name = field.name
        value = getattr(instance, field_name, None)

        if hasattr(field, "upload_to"):
            if value and hasattr(value, "url"):
                data[field_name] = value.url
            elif value and hasattr(value, "name"):
                data[field_name] = value.name
            else:
                data[field_name] = None
        elif str(field.get_internal_type()) in ["DateTimeField", "DateField"]:
            data[field_name] = value.strftime("%d/%m/%Y %H:%M") if value else None
        elif field.is_relation and value:
            data[field_name] = value.id
        else:
            data[field_name] = value
    return data
'''
# def serialize_client_with_related(client):
#     data = model_to_dict(client, fields=[field.name for field in client._meta.fields])

#     # Add related documents
#     data["client_visa"] = list(client.client_visa.all().values())
#     data["client_passport"] = list(client.client_passport.all().values())
#     data["travel_insurance"] = list(client.travel_insurance.all().values())
#     data["frequent_flyers"] = list(client.frequent_flyers.all().values())
#     data["client_documents"] = list(client.client_documents.all().values())

#     return data

# def serialize_client_with_related(client):
#     """
#     Serialize a Client instance with related objects, ensuring consistent handling of FKs and files.
#     """
#     data = {}
#     for field in client._meta.fields:
#         value = getattr(client, field.name)
#         if isinstance(field, FileField):
#             data[field.name] = value.url if value and value.name else None
#         elif field.is_relation and field.many_to_one:
#             # Handle foreign keys by serializing as IDs
#             data[field.name] = value.pk if value else None
#         else:
#             data[field.name] = value

#     # Serialize related objects as lists of dictionaries
#     # Expanded to include all mentioned nested fields; adjust as per actual models
#     data["client_visa"] = list(client.client_visa.all().values()) or []
#     data["client_passport"] = list(client.client_passport.all().values()) or []
#     data["travel_insurance"] = list(client.travel_insurance.all().values()) or []
#     data["frequent_flyers"] = list(client.frequent_flyers.all().values()) or []  # Assuming client_frequent_flyers
#     data["client_documents"] = list(client.client_documents.all().values()) or []
#     # data["client_companies"] = list(client.client_companies.all().values()) or []
#     # data["family_members"] = list(client.family_members.all().values()) or []
#     # data["fam_passport"] = list(client.fam_passport.all().values()) or []  # Assuming fam_passport is a related field
#     # data["relationsWithOthers"] = list(client.relationsWithOthers.all().values()) or []  # Assuming relationsWithOthers

#     return data

# def serialize_client_with_related(client):
#     """
#     Serialize a Client instance with related objects, ensuring consistent handling of FKs and files.
#     """
#     data = {}
#     for field in client._meta.fields:
#         value = getattr(client, field.name)
#         if isinstance(field, FileField):
#             data[field.name] = value.url if value and value.name else None
#         elif field.is_relation and field.many_to_one:
#             # Handle foreign keys by serializing as IDs
#             data[field.name] = value.pk if value else None
#         else:
#             data[field.name] = value

#     # Serialize related objects as lists of dictionaries
#     data["client_visa"] = [
#         {
#             **item,
#             'passport_size_photograph': item['passport_size_photograph'] if item.get('passport_size_photograph') else None
#         } for item in client.client_visa.all().values()
#     ] or []
#     data["client_passport"] = [
#         {
#             **item,
#             'file': item['file'] if item.get('file') else None
#         } for item in client.client_passport.all().values()
#     ] or []
#     data["travel_insurance"] = [
#         {
#             **item,
#             'file': item['file'].url if item.get('file') else None
#         } for item in client.travel_insurance.all().values()
#     ] or []
#     # data["travel_insurance"] = list(client.travel_insurance.all().values()) or []
#     data["frequent_flyers"] = list(client.frequent_flyers.all().values()) or []
#     data["client_documents"] = [
#         {
#             **item,
#             'file': item['file'] if item.get('file') else None
#         } for item in client.client_documents.all().values()
#     ] or []
    
#     return data

# def serialize_client_with_related(client):
#     data = {}
#     for field in client._meta.fields:
#         value = getattr(client, field.name)
#         if isinstance(field, models.FileField):
#             data[field.name] = value.url if value and value.name else None
#         elif field.is_relation and field.many_to_one:
#             data[field.name] = value.pk if value else None
#         else:
#             data[field.name] = value

#     data["client_passport"] = [
#         {
#             'id': item.id,
#             'passport_no': item.passport_no,
#             'passport_expiry_date': item.passport_expiry_date,
#             'passport_file': item.passport_file.url if item.passport_file else None
#         } for item in client.client_passport.all()
#     ]
#     data["client_visa"] = [
#         {
#             'id': item.id,
#             'ref_visa_country_id': item.ref_visa_country_id,
#             'visa_type': item.visa_type,
#             'visa_from_date': item.visa_from_date,
#             'visa_to_date': item.visa_to_date,
#             'passport_size_photograph': item.passport_size_photograph.url if item.passport_size_photograph else None
#         } for item in client.client_visa.all()
#     ]
#     data["travel_insurance"] = [
#         {
#             'id': item.id,
#             'insurance_from_date': item.insurance_from_date,
#             'insurance_to_date': item.insurance_to_date,
#             'insurance_document': item.insurance_document.url if item.insurance_document else None
#         } for item in client.travel_insurance.all()
#     ]
#     data["client_documents"] = [
#         {
#             'id': item.id,
#             'other_document_name': item.other_document_name,
#             'other_document': item.other_document.url if item.other_document else None
#         } for item in client.client_documents.all()
#     ]
#     data["frequent_flyers"] = [
#         {
#             'id': item.id,
#             'ref_airline_id': item.ref_airline_id,
#             'ff_no': item.ff_no
#         } for item in client.frequent_flyers.all()
#     ]
#     return data

# def serialize_client_with_related(client):
#     data = {}
#     fk_fields = ["residential_country", "residential_state", "residential_city", "ref_preferred_airline"]
#     fk_models = {
#         "residential_country": Countries,
#         "residential_state": State,
#         "residential_city": Cities,
#         "ref_preferred_airline": Airlines,
#     }
#     display_field_map = {
#         "residential_country": "name",
#         "residential_state": "name",
#         "residential_city": "name",
#         "ref_preferred_airline": "airline"  # Use 'airline' field for Airlines model
#     }

#     for field in client._meta.fields:
#         value = getattr(client, field.name)
#         if field.name in fk_fields:
#             # Get the raw ID value using the _id suffix
#             fk_value = getattr(client, f"{field.name}_id")
#             data[field.name] = fk_value  # Store numeric ID for serializer compatibility
#             if fk_value:
#                 related_model = fk_models[field.name]
#                 try:
#                     # Use prefetched related object if available
#                     related_instance = getattr(client, field.name, None)
#                     display_field = display_field_map.get(field.name, "name")
#                     data[f"{field.name}_name"] = getattr(related_instance, display_field, str(related_instance)) if related_instance else None
#                 except related_model.DoesNotExist:
#                     data[f"{field.name}_name"] = None
#             else:
#                 data[f"{field.name}_name"] = None
#         elif isinstance(field, models.FileField):
#             data[field.name] = value.url if value and hasattr(value, 'url') and value.name else None
#         elif field.is_relation and field.many_to_one and field.name not in fk_fields:
#             data[field.name] = value.pk if value else None
#         else:
#             data[field.name] = value

#     # Existing nested relationships
#     data["client_passport"] = [
#         {
#             'id': item.id,
#             'passport_no': item.passport_no,
#             'passport_expiry_date': item.passport_expiry_date,
#             'passport_file': item.passport_file.url if item.passport_file else None
#         } for item in client.client_passport.all()
#     ]
#     data["client_visa"] = [
#         {
#             'id': item.id,
#             'ref_visa_country_id': item.ref_visa_country_id,
#             'visa_type': item.visa_type,
#             'visa_from_date': item.visa_from_date,
#             'visa_to_date': item.visa_to_date,
#             'passport_size_photograph': item.passport_size_photograph.url if item.passport_size_photograph else None
#         } for item in client.client_visa.all()
#     ]
#     data["travel_insurance"] = [
#         {
#             'id': item.id,
#             'insurance_from_date': item.insurance_from_date,
#             'insurance_to_date': item.insurance_to_date,
#             'insurance_document': item.insurance_document.url if item.insurance_document else None
#         } for item in client.travel_insurance.all()
#     ]
#     data["client_documents"] = [
#         {
#             'id': item.id,
#             'other_document_name': item.other_document_name,
#             'other_document': item.other_document.url if item.other_document else None
#         } for item in client.client_documents.all()
#     ]
#     data["frequent_flyers"] = [
#         {
#             'id': item.id,
#             'ref_airline_id': item.ref_airline_id,
#             'ff_no': item.ff_no
#         } for item in client.frequent_flyers.all()
#     ]
#     return data

def serialize_client_with_related(client):
    data = {}
    fk_fields = ["country_code","residential_country", "residential_state", "residential_city", "ref_preferred_airline","ref_airline"]
    fk_models = {
        "country_code": Countries,
        "residential_country": Countries,
        "residential_state": State,
        "residential_city": Cities,
        "ref_preferred_airline": Airlines,
        "ref_airline": Airlines,
    }
    display_field_map = {
        "country_code":"country_code",
        "residential_country": "name",
        "residential_state": "name",
        "residential_city": "name",
        "ref_preferred_airline": "airline",  # Use 'airline' field for Airlines model
        "ref_airline": "airline",
    }
    

    for field in client._meta.fields:
        value = getattr(client, field.name)
        if field.name in fk_fields:
            # Get the raw ID value for reference
            fk_value = getattr(client, f"{field.name}_id")
            if fk_value:
                # Use prefetched related object if available
                related_instance = getattr(client, field.name, None)
                if related_instance:
                    display_field = display_field_map.get(field.name, "name")
                    try:
                        data[field.name] = getattr(related_instance, display_field, str(related_instance))
                    except AttributeError:
                        data[field.name] = str(related_instance)
                else:
                    # Fallback to querying if not prefetched
                    related_model = fk_models[field.name]
                    try:
                        related_instance = related_model.objects.get(pk=fk_value)
                        display_field = display_field_map.get(field.name, "name")
                        data[field.name] = getattr(related_instance, display_field, str(related_instance))
                    except related_model.DoesNotExist:
                        data[field.name] = None
            else:
                data[field.name] = None
        elif isinstance(field, models.FileField):
            data[field.name] = value.url if value and hasattr(value, 'url') and value.name else None
        elif field.is_relation and field.many_to_one and field.name not in fk_fields:
            data[field.name] = value.pk if value else None
        else:
            data[field.name] = value

    # Existing nested relationships
    data["client_passport"] = [
        {
            'id': item.id,
            'passport_no': item.passport_no,
            'passport_expiry_date': item.passport_expiry_date,
            'passport_file': item.passport_file.url if item.passport_file else None
        } for item in client.client_passport.all()
    ]
    data["client_visa"] = [
        {
            'id': item.id,
            'ref_visa_country_id': item.ref_visa_country_id,
            'visa_type': item.visa_type,
            'visa_from_date': item.visa_from_date,
            'visa_to_date': item.visa_to_date,
            'passport_size_photograph': item.passport_size_photograph.url if item.passport_size_photograph else None
        } for item in client.client_visa.all()
    ]
    data["travel_insurance"] = [
        {
            'id': item.id,
            'insurance_from_date': item.insurance_from_date,
            'insurance_to_date': item.insurance_to_date,
            'insurance_document': item.insurance_document.url if item.insurance_document else None
        } for item in client.travel_insurance.all()
    ]
    data["client_documents"] = [
        {
            'id': item.id,
            'other_document_name': item.other_document_name,
            'other_document': item.other_document.url if item.other_document else None
        } for item in client.client_documents.all()
    ]
    data["frequent_flyers"] = [
        {
            'id': item.id,
            'ref_airline_id': item.ref_airline_id,
            'ref_airline': Airlines.objects.get(id = item.ref_airline_id).airline,
            'ff_no': item.ff_no
        } for item in client.frequent_flyers.all()
    ]
    
    return data

def serialize_company_with_related(company):
    data = {}
    fk_fields = ["account_concerned_person_country_code","company_country", "company_state", "company_city","travel_concerned_person_country_code "]
    fk_models = {
        "account_concerned_person_country_code":Countries,
        "travel_concerned_person_country_code":Countries,
        "company_country": Countries,
        "company_state": State,
        "company_city": Cities,
    }
    display_field_map = {
        "account_concerned_person_country_code":"country_code",
        "travel_concerned_person_country_code":"country_code",
        "company_country": "name",
        "company_state": "name",
        "company_city": "name"
    }

    for field in company._meta.fields:
        value = getattr(company, field.name)
        if field.name in fk_fields:
            # Get the raw ID value for reference
            fk_value = getattr(company, f"{field.name}_id")
            if fk_value:
                # Use prefetched related object if available
                related_instance = getattr(company, field.name, None)
                if related_instance:
                    display_field = display_field_map.get(field.name, "name")
                    try:
                        data[field.name] = getattr(related_instance, display_field, str(related_instance))
                    except AttributeError:
                        data[field.name] = str(related_instance)
                else:
                    # Fallback to querying if not prefetched
                    related_model = fk_models[field.name]
                    try:
                        related_instance = related_model.objects.get(pk=fk_value)
                        display_field = display_field_map.get(field.name, "name")
                        data[field.name] = getattr(related_instance, display_field, str(related_instance))
                    except related_model.DoesNotExist:
                        data[field.name] = None
            else:
                data[field.name] = None
        elif isinstance(field, models.FileField):
            data[field.name] = value.url if value and hasattr(value, 'url') and value.name else None
        elif field.is_relation and field.many_to_one and field.name not in fk_fields:
            data[field.name] = value.pk if value else None
        else:
            data[field.name] = value
    
    return data

