"""
Salesforce GUI Integration for FoundryMatch
===========================================
GUI components for Salesforce integration with the existing FoundryMatch interface.
"""

import asyncio
import logging
import tkinter as tk
from tkinter import ttk, messagebox
from typing import List, Optional
import threading
import pandas as pd

from .core import (
    SalesforceIntegration,
    SalesforceCredentials,
    SalesforceObject,
    SalesforceField,
    ApiLimits,
)

log = logging.getLogger(__name__)


class SalesforceConnectionDialog(tk.Toplevel):
    """Dialog for managing Salesforce connections."""

    def __init__(
        self, parent, existing_credentials: Optional[SalesforceCredentials] = None
    ):
        super().__init__(parent)
        self.parent = parent
        self.result = None
        self.sf_integration = None
        self.existing_credentials = existing_credentials

        # UI setup
        self.title("Salesforce Connection")
        self.geometry("700x600")  # <- Make it bigger
        self.resizable(True, True)  # <- Allow resizing
        self.transient(parent)
        self.grab_set()

        # Variables
        self.client_id_var = tk.StringVar()
        self.client_secret_var = tk.StringVar()
        self.is_sandbox_var = tk.BooleanVar()
        self.connection_status_var = tk.StringVar(value="Not connected")

        # Load existing credentials if provided
        if existing_credentials:
            self.client_id_var.set(existing_credentials.client_id)
            self.client_secret_var.set(existing_credentials.client_secret)
            self.is_sandbox_var.set(existing_credentials.is_sandbox)

            if existing_credentials.access_token:
                self.connection_status_var.set(
                    f"Connected to: {existing_credentials.username or 'Unknown'}"
                )

        self._build_ui()
        self._center_window()

    def _build_ui(self):
        """Build the connection dialog UI."""
        main_frame = ttk.Frame(self, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # Title
        title_label = ttk.Label(
            main_frame,
            text="Salesforce Connection Setup",
            font=("TkDefaultFont", 14, "bold"),
        )
        title_label.pack(pady=(0, 20))

        # Instructions
        instructions = (
            "Enter your Salesforce Connected App credentials to establish a connection.\n"
            "You'll need to create a Connected App in your Salesforce org with OAuth enabled."
        )
        ttk.Label(main_frame, text=instructions, wraplength=550).pack(pady=(0, 20))

        # Credentials frame
        cred_frame = ttk.LabelFrame(
            main_frame, text="Connected App Credentials", padding="15"
        )
        cred_frame.pack(fill=tk.X, pady=(0, 20))

        # Client ID
        ttk.Label(cred_frame, text="Client ID (Consumer Key):").pack(anchor=tk.W)
        self.client_id_entry = ttk.Entry(
            cred_frame, textvariable=self.client_id_var, width=60
        )
        self.client_id_entry.pack(fill=tk.X, pady=(5, 15))

        # Client Secret
        ttk.Label(cred_frame, text="Client Secret (Consumer Secret):").pack(anchor=tk.W)
        self.client_secret_entry = ttk.Entry(
            cred_frame, textvariable=self.client_secret_var, show="*", width=60
        )
        self.client_secret_entry.pack(fill=tk.X, pady=(5, 15))

        # Sandbox checkbox
        self.sandbox_check = ttk.Checkbutton(
            cred_frame,
            text="Connect to Sandbox Environment",
            variable=self.is_sandbox_var,
        )
        self.sandbox_check.pack(anchor=tk.W)

        # Connection status frame
        status_frame = ttk.LabelFrame(
            main_frame, text="Connection Status", padding="15"
        )
        status_frame.pack(fill=tk.X, pady=(0, 20))

        self.status_label = ttk.Label(
            status_frame,
            textvariable=self.connection_status_var,
            font=("TkDefaultFont", 10, "bold"),
        )
        self.status_label.pack(anchor=tk.W)

        # API limits display (initially hidden)
        self.limits_frame = ttk.Frame(status_frame)
        self.limits_text = tk.Text(
            self.limits_frame, height=4, width=60, state=tk.DISABLED
        )
        self.limits_text.pack(fill=tk.X)

        # Buttons frame
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(20, 0))

        # Left side buttons
        left_buttons = ttk.Frame(button_frame)
        left_buttons.pack(side=tk.LEFT)

        self.connect_btn = ttk.Button(
            left_buttons,
            text="Connect to Salesforce",
            command=self._connect_to_salesforce,
            style="Primary.TButton",
        )
        self.connect_btn.pack(side=tk.LEFT, padx=(0, 10))

        self.test_btn = ttk.Button(
            left_buttons,
            text="Test Connection",
            command=self._test_connection,
            state=tk.DISABLED,
        )
        self.test_btn.pack(side=tk.LEFT, padx=(0, 10))

        # Help button
        self.help_btn = ttk.Button(
            left_buttons, text="Setup Help", command=self._show_setup_help
        )
        self.help_btn.pack(side=tk.LEFT)

        # Right side buttons
        right_buttons = ttk.Frame(button_frame)
        right_buttons.pack(side=tk.RIGHT)

        ttk.Button(right_buttons, text="Cancel", command=self._cancel).pack(
            side=tk.RIGHT, padx=(10, 0)
        )

        self.ok_btn = ttk.Button(
            right_buttons,
            text="OK",
            command=self._ok,
            state=tk.DISABLED,
            style="Primary.TButton",
        )
        self.ok_btn.pack(side=tk.RIGHT)

        # Initialize connection if credentials exist
        if self.existing_credentials and self.existing_credentials.access_token:
            self._initialize_existing_connection()

    def _connect_to_salesforce(self):
        """Handle connection to Salesforce."""
        if not self.client_id_var.get() or not self.client_secret_var.get():
            messagebox.showwarning(
                "Missing Credentials", "Please enter both Client ID and Client Secret"
            )
            return

        # Disable button and show progress
        self.connect_btn.config(state=tk.DISABLED, text="Connecting...")
        self.update()

        # Run connection in background thread
        def connect_async():
            try:
                # Create new integration
                self.sf_integration = SalesforceIntegration()

                # Run OAuth flow
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)

                success = loop.run_until_complete(
                    self.sf_integration.authenticate_oauth(
                        self.client_id_var.get(),
                        self.client_secret_var.get(),
                        self.is_sandbox_var.get(),
                    )
                )

                loop.close()

                # Update UI on main thread
                self.after(0, self._handle_connection_result, success)

            except Exception as e:
                log.error(f"Connection error: {e}", exc_info=True)
                self.after(0, self._handle_connection_result, False, str(e))

        threading.Thread(target=connect_async, daemon=True).start()

    def _handle_connection_result(self, success: bool, error: str = None):
        """Handle the result of connection attempt."""
        self.connect_btn.config(state=tk.NORMAL, text="Connect to Salesforce")

        if success:
            self.connection_status_var.set(
                f"✓ Connected to: {self.sf_integration.credentials.username or 'Salesforce'}"
            )
            self.status_label.config(foreground="green")
            self.test_btn.config(state=tk.NORMAL)
            self.ok_btn.config(state=tk.NORMAL)

            # Show API limits
            self._update_api_limits_display()

        else:
            error_msg = "✗ Connection failed"
            if error:
                error_msg += f": {error}"
            self.connection_status_var.set(error_msg)
            self.status_label.config(foreground="red")

            messagebox.showerror(
                "Connection Failed",
                f"Failed to connect to Salesforce.\n\n{error or 'Unknown error'}",
            )

    def _test_connection(self):
        """Test the current connection."""
        if not self.sf_integration:
            return

        self.test_btn.config(state=tk.DISABLED, text="Testing...")

        def test_async():
            try:
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)

                connected, message = loop.run_until_complete(
                    self.sf_integration.test_connection()
                )

                loop.close()
                self.after(0, self._handle_test_result, connected, message)

            except Exception as e:
                log.error(f"Test error: {e}", exc_info=True)
                self.after(0, self._handle_test_result, False, str(e))

        threading.Thread(target=test_async, daemon=True).start()

    def _handle_test_result(self, success: bool, message: str):
        """Handle test connection result."""
        self.test_btn.config(state=tk.NORMAL, text="Test Connection")

        if success:
            messagebox.showinfo(
                "Connection Test", f"✓ Connection successful!\n\n{message}"
            )
            self._update_api_limits_display()
        else:
            messagebox.showerror(
                "Connection Test", f"✗ Connection test failed!\n\n{message}"
            )

    def _update_api_limits_display(self):
        """Update the API limits display."""
        if not self.sf_integration:
            return

        def get_limits_async():
            try:
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)

                limits = loop.run_until_complete(self.sf_integration.get_api_limits())

                loop.close()
                self.after(0, self._display_limits, limits)

            except Exception as e:
                log.error(f"Error getting limits: {e}", exc_info=True)

        threading.Thread(target=get_limits_async, daemon=True).start()

    def _display_limits(self, limits: Optional[ApiLimits]):
        """Display API limits in the UI."""
        if not limits:
            return

        self.limits_frame.pack(fill=tk.X, pady=(10, 0))

        limits_text = (
            f"API Requests: {limits.daily_api_requests_used:,} / {limits.daily_api_requests_max:,} "
            f"({limits.api_usage_percentage:.1f}%)\n"
            f"Bulk API Requests: {limits.daily_bulk_api_requests_used:,} / {limits.daily_bulk_api_requests_max:,} "
            f"({limits.bulk_api_usage_percentage:.1f}%)"
        )

        self.limits_text.config(state=tk.NORMAL)
        self.limits_text.delete(1.0, tk.END)
        self.limits_text.insert(1.0, limits_text)
        self.limits_text.config(state=tk.DISABLED)

    def _initialize_existing_connection(self):
        """Initialize UI for existing connection."""
        self.sf_integration = SalesforceIntegration(self.existing_credentials)
        self.test_btn.config(state=tk.NORMAL)
        self.ok_btn.config(state=tk.NORMAL)
        self.status_label.config(foreground="green")

    def _show_setup_help(self):
        """Show setup help dialog."""
        help_text = """
Setting up Salesforce Connected App:

1. Log into your Salesforce org as an administrator
2. Go to Setup -> Apps -> App Manager
3. Click "New Connected App"
4. Fill in the basic information:
   - Connected App Name: FoundryMatch Integration
   - API Name: FoundryMatch_Integration
   - Contact Email: your email

5. In the OAuth Settings section:
   - Check "Enable OAuth Settings"
   - Callback URL: http://localhost:8080/oauth/callback
   - Selected OAuth Scopes: Add "Full access (full)" and "Perform requests on your behalf at any time (refresh_token, offline_access)"

6. Save the Connected App
7. Copy the Consumer Key (Client ID) and Consumer Secret (Client Secret)
8. You may need to wait 2-10 minutes for the Connected App to be activated

Note: For production use, configure IP restrictions and other security settings as needed.
        """

        help_dialog = tk.Toplevel(self)
        help_dialog.title("Salesforce Setup Help")
        help_dialog.geometry("700x500")
        help_dialog.transient(self)

        text_widget = tk.Text(help_dialog, wrap=tk.WORD, padx=20, pady=20)
        text_widget.pack(fill=tk.BOTH, expand=True)
        text_widget.insert(1.0, help_text)
        text_widget.config(state=tk.DISABLED)

        ttk.Button(help_dialog, text="Close", command=help_dialog.destroy).pack(pady=10)

    def _ok(self):
        """Handle OK button."""
        if self.sf_integration and self.sf_integration.is_connected():
            self.result = self.sf_integration.credentials
            self.destroy()
        else:
            messagebox.showwarning(
                "Not Connected", "Please establish a connection first"
            )

    def _cancel(self):
        """Handle Cancel button."""
        self.result = None
        self.destroy()

    def _center_window(self):
        """Center the window on the parent."""
        self.update_idletasks()
        x = (
            self.parent.winfo_x()
            + (self.parent.winfo_width() // 2)
            - (self.winfo_width() // 2)
        )
        y = (
            self.parent.winfo_y()
            + (self.parent.winfo_height() // 2)
            - (self.winfo_height() // 2)
        )
        self.geometry(f"+{x}+{y}")


class SalesforceObjectSelector(ttk.Frame):
    """Widget for selecting Salesforce objects and fields."""

    def __init__(self, parent, sf_integration: SalesforceIntegration, **kwargs):
        super().__init__(parent, **kwargs)
        self.sf_integration = sf_integration
        self.selected_object = None
        self.selected_fields = []

        # Variables
        self.object_var = tk.StringVar()
        self.filter_var = tk.StringVar()

        # Object list
        self.objects = []
        self.filtered_objects = []

        self._build_ui()
        self._load_objects()

    def _build_ui(self):
        """Build the object selector UI."""
        # Object selection frame
        obj_frame = ttk.LabelFrame(self, text="Select Salesforce Object", padding="10")
        obj_frame.pack(fill=tk.X, pady=(0, 10))

        # Search/filter
        filter_frame = ttk.Frame(obj_frame)
        filter_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(filter_frame, text="Filter objects:").pack(side=tk.LEFT, padx=(0, 5))

        self.filter_entry = ttk.Entry(filter_frame, textvariable=self.filter_var)
        self.filter_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
        self.filter_entry.bind("<KeyRelease>", self._on_filter_change)

        # Show custom only checkbox
        self.custom_only_var = tk.BooleanVar()
        ttk.Checkbutton(
            filter_frame,
            text="Custom objects only",
            variable=self.custom_only_var,
            command=self._on_filter_change,
        ).pack(side=tk.RIGHT)

        # Object listbox
        list_frame = ttk.Frame(obj_frame)
        list_frame.pack(fill=tk.BOTH, expand=True)

        self.object_listbox = tk.Listbox(list_frame, height=8)
        self.object_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.object_listbox.bind("<<ListboxSelect>>", self._on_object_select)

        obj_scrollbar = ttk.Scrollbar(
            list_frame, orient=tk.VERTICAL, command=self.object_listbox.yview
        )
        obj_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.object_listbox.config(yscrollcommand=obj_scrollbar.set)

        # Fields selection frame
        self.fields_frame = ttk.LabelFrame(self, text="Available Fields", padding="10")
        self.fields_frame.pack(fill=tk.BOTH, expand=True)

        # Field filter
        field_filter_frame = ttk.Frame(self.fields_frame)
        field_filter_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(field_filter_frame, text="Filter fields:").pack(
            side=tk.LEFT, padx=(0, 5)
        )

        self.field_filter_var = tk.StringVar()
        self.field_filter_entry = ttk.Entry(
            field_filter_frame, textvariable=self.field_filter_var
        )
        self.field_filter_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
        self.field_filter_entry.bind("<KeyRelease>", self._on_field_filter_change)

        # Fields treeview
        fields_tree_frame = ttk.Frame(self.fields_frame)
        fields_tree_frame.pack(fill=tk.BOTH, expand=True)

        columns = ("name", "label", "type", "required")
        self.fields_tree = ttk.Treeview(
            fields_tree_frame, columns=columns, show="headings", height=10
        )

        # Configure columns
        self.fields_tree.heading("name", text="API Name")
        self.fields_tree.heading("label", text="Label")
        self.fields_tree.heading("type", text="Type")
        self.fields_tree.heading("required", text="Required")

        self.fields_tree.column("name", width=150)
        self.fields_tree.column("label", width=200)
        self.fields_tree.column("type", width=100)
        self.fields_tree.column("required", width=80)

        self.fields_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        fields_scrollbar = ttk.Scrollbar(
            fields_tree_frame, orient=tk.VERTICAL, command=self.fields_tree.yview
        )
        fields_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.fields_tree.config(yscrollcommand=fields_scrollbar.set)

        # Selection info
        self.selection_label = ttk.Label(self.fields_frame, text="No object selected")
        self.selection_label.pack(pady=(10, 0))

    def _load_objects(self):
        """Load Salesforce objects asynchronously."""

        def load_async():
            try:
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)

                objects = loop.run_until_complete(self.sf_integration.get_objects())

                loop.close()
                self.after(0, self._populate_objects, objects)

            except Exception as e:
                log.error(f"Error loading objects: {e}", exc_info=True)
                self.after(0, self._show_load_error, str(e))

        # Show loading message
        self.object_listbox.delete(0, tk.END)
        self.object_listbox.insert(0, "Loading objects...")

        threading.Thread(target=load_async, daemon=True).start()

    def _populate_objects(self, objects: List[SalesforceObject]):
        """Populate the objects list."""
        self.objects = objects
        self._update_object_list()

    def _show_load_error(self, error: str):
        """Show error loading objects."""
        self.object_listbox.delete(0, tk.END)
        self.object_listbox.insert(0, f"Error loading objects: {error}")

    def _update_object_list(self):
        """Update the filtered object list."""
        self.object_listbox.delete(0, tk.END)

        filter_text = self.filter_var.get().lower()
        custom_only = self.custom_only_var.get()

        self.filtered_objects = []
        for obj in self.objects:
            # Apply filters
            if custom_only and not obj.custom:
                continue

            if (
                filter_text
                and filter_text not in obj.label.lower()
                and filter_text not in obj.name.lower()
            ):
                continue

            self.filtered_objects.append(obj)

            # Display format: "Label (API_Name)"
            display_text = f"{obj.label} ({obj.name})"
            if obj.custom:
                display_text += " [Custom]"

            self.object_listbox.insert(tk.END, display_text)

    def _on_filter_change(self, event=None):
        """Handle filter change."""
        self._update_object_list()

    def _on_object_select(self, event=None):
        """Handle object selection."""
        selection = self.object_listbox.curselection()
        if not selection:
            return

        idx = selection[0]
        if 0 <= idx < len(self.filtered_objects):
            self.selected_object = self.filtered_objects[idx]
            self._load_object_fields()

    def _load_object_fields(self):
        """Load fields for the selected object."""
        if not self.selected_object:
            return

        # Clear current fields
        for item in self.fields_tree.get_children():
            self.fields_tree.delete(item)

        self.selection_label.config(
            text=f"Loading fields for {self.selected_object.label}..."
        )

        def load_fields_async():
            try:
                loop = asyncio.new_event_loop()
                asyncio.set_event_loop(loop)

                fields = loop.run_until_complete(
                    self.sf_integration.get_object_fields(self.selected_object.name)
                )

                loop.close()
                self.after(0, self._populate_fields, fields)

            except Exception as e:
                log.error(f"Error loading fields: {e}", exc_info=True)
                self.after(0, self._show_field_error, str(e))

        threading.Thread(target=load_fields_async, daemon=True).start()

    def _populate_fields(self, fields: List[SalesforceField]):
        """Populate the fields tree."""
        self.selected_object.fields = fields
        self._update_fields_tree()

    def _show_field_error(self, error: str):
        """Show error loading fields."""
        self.selection_label.config(text=f"Error loading fields: {error}")

    def _update_fields_tree(self):
        """Update the fields tree view."""
        # Clear existing items
        for item in self.fields_tree.get_children():
            self.fields_tree.delete(item)

        if not self.selected_object or not self.selected_object.fields:
            return

        filter_text = self.field_filter_var.get().lower()

        for field in self.selected_object.fields:
            # Apply filter
            if filter_text and (
                filter_text not in field.label.lower()
                and filter_text not in field.name.lower()
            ):
                continue

            # Determine if required
            required = "Yes" if not field.nullable else "No"

            self.fields_tree.insert(
                "", tk.END, values=(field.name, field.label, field.type, required)
            )

        self.selection_label.config(
            text=f"Selected: {self.selected_object.label} ({len(self.selected_object.fields)} fields)"
        )

    def _on_field_filter_change(self, event=None):
        """Handle field filter change."""
        self._update_fields_tree()

    def get_selected_object(self) -> Optional[SalesforceObject]:
        """Get the currently selected object."""
        return self.selected_object

    def get_selected_fields(self) -> List[str]:
        """Get the selected field names."""
        selected_items = self.fields_tree.selection()
        field_names = []

        for item in selected_items:
            values = self.fields_tree.item(item, "values")
            if values:
                field_names.append(values[0])  # API name is first column

        return field_names


def add_salesforce_integration_to_gui(app, notebook: ttk.Notebook):
    """Add Salesforce integration tab to the existing GUI."""

    # Create Salesforce tab
    sf_tab = ttk.Frame(notebook)
    notebook.add(sf_tab, text="Salesforce")

    # Add Salesforce connection management
    connection_frame = ttk.LabelFrame(
        sf_tab, text="Salesforce Connection", padding="10"
    )
    connection_frame.pack(fill=tk.X, padx=10, pady=10)

    # Connection status
    app.sf_status_var = tk.StringVar(value="Not connected")
    status_label = ttk.Label(connection_frame, textvariable=app.sf_status_var)
    status_label.pack(side=tk.LEFT, padx=(0, 20))

    # Connection buttons
    app.sf_connect_btn = ttk.Button(
        connection_frame,
        text="Connect to Salesforce",
        command=lambda: show_salesforce_connection_dialog(app),
    )
    app.sf_connect_btn.pack(side=tk.LEFT, padx=5)

    app.sf_disconnect_btn = ttk.Button(
        connection_frame,
        text="Disconnect",
        command=lambda: disconnect_salesforce(app),
        state=tk.DISABLED,
    )
    app.sf_disconnect_btn.pack(side=tk.LEFT, padx=5)

    # Data source selection
    app.sf_data_frame = ttk.LabelFrame(
        sf_tab, text="Salesforce Data Source", padding="10"
    )
    app.sf_data_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

    # Initially disabled
    for widget in app.sf_data_frame.winfo_children():
        widget.configure(state=tk.DISABLED)

    # Initialize Salesforce integration variables
    app.sf_integration = None
    app.sf_credentials = None


def show_salesforce_connection_dialog(app):
    """Show the Salesforce connection dialog."""
    dialog = SalesforceConnectionDialog(app, app.sf_credentials)
    app.wait_window(dialog)

    if dialog.result:
        app.sf_credentials = dialog.result
        app.sf_integration = SalesforceIntegration(app.sf_credentials)

        # Update UI
        app.sf_status_var.set(f"✓ Connected: {dialog.result.username or 'Salesforce'}")
        app.sf_connect_btn.config(text="Reconnect")
        app.sf_disconnect_btn.config(state=tk.NORMAL)

        # Enable data source selection
        setup_salesforce_data_source(app)


def disconnect_salesforce(app):
    """Disconnect from Salesforce."""
    app.sf_integration = None
    app.sf_credentials = None
    app.sf_status_var.set("Not connected")
    app.sf_connect_btn.config(text="Connect to Salesforce")
    app.sf_disconnect_btn.config(state=tk.DISABLED)

    # Clear data source
    for widget in app.sf_data_frame.winfo_children():
        widget.destroy()


def setup_salesforce_data_source(app):
    """Setup the Salesforce data source selection."""
    # Clear existing widgets
    for widget in app.sf_data_frame.winfo_children():
        widget.destroy()

    # Create object selector
    app.sf_object_selector = SalesforceObjectSelector(
        app.sf_data_frame, app.sf_integration
    )
    app.sf_object_selector.pack(fill=tk.BOTH, expand=True)

    # Add action buttons
    action_frame = ttk.Frame(app.sf_data_frame)
    action_frame.pack(fill=tk.X, pady=(10, 0))

    ttk.Button(
        action_frame,
        text="Load as Source Data",
        command=lambda: load_salesforce_data_as_source(app),
        style="Primary.TButton",
    ).pack(side=tk.LEFT, padx=5)

    ttk.Button(
        action_frame,
        text="Load as Reference Data",
        command=lambda: load_salesforce_data_as_reference(app),
    ).pack(side=tk.LEFT, padx=5)


def load_salesforce_data_as_source(app):
    """Load selected Salesforce data as source."""
    selected_object = app.sf_object_selector.get_selected_object()
    if not selected_object:
        messagebox.showwarning(
            "No Selection", "Please select a Salesforce object first"
        )
        return

    # Get selected fields or use default set
    selected_fields = app.sf_object_selector.get_selected_fields()
    if not selected_fields:
        # Use a default set of common fields
        default_fields = ["Id", "Name", "CreatedDate", "LastModifiedDate"]
        available_field_names = [f.name for f in selected_object.fields]
        selected_fields = [f for f in default_fields if f in available_field_names]

        if not selected_fields:
            # Fall back to first 10 fields
            selected_fields = available_field_names[:10]

    # Build SOQL query
    fields_str = ", ".join(selected_fields)
    soql = f"SELECT {fields_str} FROM {selected_object.name} LIMIT 10000"

    # Load data asynchronously
    load_salesforce_data(app, soql, is_source=True, object_name=selected_object.name)


def load_salesforce_data_as_reference(app):
    """Load selected Salesforce data as reference."""
    selected_object = app.sf_object_selector.get_selected_object()
    if not selected_object:
        messagebox.showwarning(
            "No Selection", "Please select a Salesforce object first"
        )
        return

    # Similar to source loading
    selected_fields = app.sf_object_selector.get_selected_fields()
    if not selected_fields:
        default_fields = ["Id", "Name", "CreatedDate", "LastModifiedDate"]
        available_field_names = [f.name for f in selected_object.fields]
        selected_fields = [f for f in default_fields if f in available_field_names]

        if not selected_fields:
            selected_fields = available_field_names[:10]

    fields_str = ", ".join(selected_fields)
    soql = f"SELECT {fields_str} FROM {selected_object.name} LIMIT 10000"

    load_salesforce_data(app, soql, is_source=False, object_name=selected_object.name)


def load_salesforce_data(app, soql: str, is_source: bool, object_name: str):
    """Load data from Salesforce using SOQL."""

    def load_async():
        try:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)

            df = loop.run_until_complete(app.sf_integration.query_data(soql))

            loop.close()
            app.after(0, handle_salesforce_data_loaded, df, is_source, object_name)

        except Exception as e:
            log.error(f"Error loading Salesforce data: {e}", exc_info=True)
            app.after(0, handle_salesforce_load_error, str(e))

    def handle_salesforce_data_loaded(
        df: Optional[pd.DataFrame], is_source: bool, object_name: str
    ):
        """Handle successful data load."""
        if df is not None and not df.empty:
            if is_source:
                app.source_df = df
                app.src_path = f"Salesforce:{object_name}"
                if hasattr(app, "lbl_src"):
                    app.lbl_src.config(
                        text=f"Salesforce {object_name} ({len(df):,} records)"
                    )

                # Auto-select ID column
                if "Id" in df.columns:
                    app.source_id_var.set("Id")
            else:
                app.ref_df = df
                app.ref_path = f"Salesforce:{object_name}"
                if hasattr(app, "lbl_ref"):
                    app.lbl_ref.config(
                        text=f"Salesforce {object_name} ({len(df):,} records)"
                    )

                # Auto-select ID column
                if "Id" in df.columns:
                    app.ref_id_var.set("Id")

            # Update UI
            if hasattr(app, "_populate_column_trees"):
                app._populate_column_trees()
            if hasattr(app, "refresh_ui"):
                app.refresh_ui()

            messagebox.showinfo(
                "Data Loaded",
                f"Successfully loaded {len(df):,} records from Salesforce {object_name}",
            )
        else:
            messagebox.showwarning("No Data", "No data returned from Salesforce query")

    def handle_salesforce_load_error(error: str):
        """Handle data load error."""
        messagebox.showerror(
            "Load Error", f"Failed to load Salesforce data:\n\n{error}"
        )

    # Show loading message
    data_type = "source" if is_source else "reference"
    if hasattr(app, "threadsafe_update_status"):
        app.threadsafe_update_status(f"Loading Salesforce data as {data_type}...")

    threading.Thread(target=load_async, daemon=True).start()
