"""
HubSpot GUI integration module for FoundryOps FuzzyMatcher desktop application.
Provides Tkinter dialogs and widgets for HubSpot operations.
"""

import asyncio
import logging
import tkinter as tk
from tkinter import ttk, messagebox
from typing import List, Optional, Tuple


from .core import HubSpotIntegration, HubSpotCredentials, ApiLimits
from .workflows import (
    HubSpotWorkflowEngine,
)

logger = logging.getLogger(__name__)


class HubSpotConnectionDialog(tk.Toplevel):
    """Dialog for HubSpot OAuth connection setup."""

    def __init__(self, parent, credentials: Optional[HubSpotCredentials] = None):
        super().__init__(parent)
        self.parent = parent
        self.credentials = credentials
        self.result = None

        self.title("Connect to HubSpot")
        self.geometry("500x450")
        self.resizable(False, False)

        # Make dialog modal
        self.transient(parent)
        self.grab_set()

        self._create_widgets()
        self._load_credentials()

        # Center dialog
        self.update_idletasks()
        x = (self.winfo_screenwidth() - self.winfo_width()) // 2
        y = (self.winfo_screenheight() - self.winfo_height()) // 2
        self.geometry(f"+{x}+{y}")

    def _create_widgets(self):
        """Create dialog widgets."""
        # Header with HubSpot branding
        header_frame = ttk.Frame(self)
        header_frame.pack(fill=tk.X, padx=20, pady=(20, 10))

        ttk.Label(
            header_frame, text="HubSpot Integration", font=("Arial", 16, "bold")
        ).pack(side=tk.LEFT)

        # Connection type selection
        type_frame = ttk.LabelFrame(self, text="Connection Type", padding=10)
        type_frame.pack(fill=tk.X, padx=20, pady=10)

        self.connection_type = tk.StringVar(value="oauth")

        ttk.Radiobutton(
            type_frame,
            text="OAuth 2.0 (Recommended)",
            variable=self.connection_type,
            value="oauth",
            command=self._on_type_change,
        ).pack(anchor=tk.W)

        ttk.Radiobutton(
            type_frame,
            text="Private App Token",
            variable=self.connection_type,
            value="private",
            command=self._on_type_change,
        ).pack(anchor=tk.W)

        # OAuth frame
        self.oauth_frame = ttk.LabelFrame(self, text="OAuth Settings", padding=10)
        self.oauth_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        # Client ID
        ttk.Label(self.oauth_frame, text="Client ID:").grid(
            row=0, column=0, sticky=tk.W, pady=5
        )
        self.client_id_var = tk.StringVar()
        self.client_id_entry = ttk.Entry(
            self.oauth_frame, textvariable=self.client_id_var, width=40
        )
        self.client_id_entry.grid(row=0, column=1, pady=5, padx=(10, 0))

        # Client Secret (optional)
        ttk.Label(self.oauth_frame, text="Client Secret (optional):").grid(
            row=1, column=0, sticky=tk.W, pady=5
        )
        self.client_secret_var = tk.StringVar()
        self.client_secret_entry = ttk.Entry(
            self.oauth_frame, textvariable=self.client_secret_var, width=40, show="*"
        )
        self.client_secret_entry.grid(row=1, column=1, pady=5, padx=(10, 0))

        # Redirect URI
        ttk.Label(self.oauth_frame, text="Redirect URI:").grid(
            row=2, column=0, sticky=tk.W, pady=5
        )
        self.redirect_uri_var = tk.StringVar(value="http://localhost:8089/callback")
        self.redirect_uri_entry = ttk.Entry(
            self.oauth_frame, textvariable=self.redirect_uri_var, width=40
        )
        self.redirect_uri_entry.grid(row=2, column=1, pady=5, padx=(10, 0))

        # Private app frame
        self.private_frame = ttk.LabelFrame(
            self, text="Private App Settings", padding=10
        )

        ttk.Label(self.private_frame, text="Access Token:").grid(
            row=0, column=0, sticky=tk.W, pady=5
        )
        self.access_token_var = tk.StringVar()
        self.access_token_entry = ttk.Entry(
            self.private_frame, textvariable=self.access_token_var, width=40, show="*"
        )
        self.access_token_entry.grid(row=0, column=1, pady=5, padx=(10, 0))

        # Help text
        help_frame = ttk.Frame(self)
        help_frame.pack(fill=tk.X, padx=20, pady=(0, 10))

        self.help_label = ttk.Label(
            help_frame,
            text="OAuth 2.0 provides secure, multi-portal access without sharing credentials.",
            wraplength=450,
            foreground="gray",
        )
        self.help_label.pack()

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

        ttk.Button(button_frame, text="Cancel", command=self.destroy).pack(
            side=tk.RIGHT, padx=(5, 0)
        )

        self.connect_button = ttk.Button(
            button_frame, text="Connect", command=self._connect, style="Accent.TButton"
        )
        self.connect_button.pack(side=tk.RIGHT)

        # Status label
        self.status_label = ttk.Label(button_frame, text="", foreground="green")
        self.status_label.pack(side=tk.LEFT)

        # Initialize view
        self._on_type_change()

    def _on_type_change(self):
        """Handle connection type change."""
        if self.connection_type.get() == "oauth":
            self.oauth_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
            self.private_frame.pack_forget()
            self.help_label.config(
                text="OAuth 2.0 provides secure, multi-portal access without sharing credentials."
            )
        else:
            self.private_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
            self.oauth_frame.pack_forget()
            self.help_label.config(
                text="Private app tokens are ideal for single-portal or automated workflows."
            )

    def _load_credentials(self):
        """Load existing credentials if available."""
        if self.credentials:
            if self.credentials.use_private_app:
                self.connection_type.set("private")
                self.access_token_var.set(self.credentials.access_token or "")
            else:
                self.connection_type.set("oauth")
                self.client_id_var.set(self.credentials.client_id or "")
                self.client_secret_var.set(self.credentials.client_secret or "")
                self.redirect_uri_var.set(
                    self.credentials.redirect_uri or "http://localhost:8089/callback"
                )
            self._on_type_change()

    def _connect(self):
        """Handle connection button click."""
        self.connect_button.config(state="disabled")
        self.status_label.config(text="Connecting...", foreground="blue")

        # Run connection in thread to avoid blocking GUI
        self.after(100, self._run_connection)

    def _run_connection(self):
        """Run the connection process."""
        try:
            if self.connection_type.get() == "oauth":
                # Validate inputs
                if not self.client_id_var.get():
                    raise ValueError("Client ID is required")

                credentials = HubSpotCredentials(
                    client_id=self.client_id_var.get(),
                    client_secret=self.client_secret_var.get(),
                    redirect_uri=self.redirect_uri_var.get(),
                    use_private_app=False,
                )

                # Create integration and perform OAuth
                integration = HubSpotIntegration(credentials)

                # Run OAuth in thread
                import threading

                auth_result = {"success": False, "error": None, "credentials": None}

                def run_oauth():
                    try:
                        loop = asyncio.new_event_loop()
                        asyncio.set_event_loop(loop)
                        success = loop.run_until_complete(
                            integration.authenticate_oauth()
                        )
                        if success:
                            auth_result["success"] = True
                            auth_result["credentials"] = integration.credentials
                        else:
                            auth_result["error"] = "OAuth authentication failed"
                    finally:
                        loop.close()
                        asyncio.set_event_loop(None)

                auth_thread = threading.Thread(target=run_oauth)
                auth_thread.start()

                # Poll thread without blocking UI
                self._poll_thread(auth_thread, auth_result)

            else:
                # Private app - test the token
                if not self.access_token_var.get():
                    raise ValueError("Access token is required")

                credentials = HubSpotCredentials(
                    client_id="private_app",
                    access_token=self.access_token_var.get(),
                    use_private_app=True,
                )

                # Test connection in thread
                test_result = {"success": False, "error": None}

                def test_connection():
                    integration = None
                    try:
                        integration = HubSpotIntegration(credentials)
                        loop = asyncio.new_event_loop()
                        asyncio.set_event_loop(loop)
                        loop.run_until_complete(integration.connect())
                        loop.run_until_complete(integration._get_portal_info())
                        test_result["success"] = (
                            integration.credentials.portal_id is not None
                        )
                        test_result["credentials"] = integration.credentials
                    except Exception as e:
                        test_result["error"] = str(e)
                    finally:
                        if integration and integration.session:
                            loop.run_until_complete(integration.disconnect())
                        loop.close()
                        asyncio.set_event_loop(None)

                test_thread = threading.Thread(target=test_connection)
                test_thread.start()
                self._poll_thread(test_thread, test_result)

        except Exception as e:
            logger.error(f"Connection error: {e}")
            self.status_label.config(text=f"Error: {str(e)}", foreground="red")
            self.connect_button.config(state="normal")

    def _poll_thread(self, thread, result_dict):
        """Poll thread completion without blocking UI."""
        if thread.is_alive():
            self.after(250, lambda: self._poll_thread(thread, result_dict))
            return

        # Thread complete - handle result
        if result_dict.get("success"):
            self.result = result_dict.get("credentials")
            self.status_label.config(text="Connected successfully!", foreground="green")
            # Update status in main window if available
            if hasattr(self.parent, "update_hubspot_status"):
                self.parent.after(100, lambda: update_hubspot_status(self.parent, True))
            self.after(1000, self.destroy)
        else:
            error = result_dict.get("error", "Authentication failed")
            logger.error(f"Connection failed: {error}")
            self.status_label.config(text=f"Error: {error}", foreground="red")
            self.connect_button.config(state="normal")


class HubSpotObjectPicker(tk.Toplevel):
    """Dialog for selecting HubSpot objects and properties."""

    def __init__(self, parent, integration: HubSpotIntegration):
        super().__init__(parent)
        self.parent = parent
        self.integration = integration
        self.selected_object = None
        self.selected_properties = []

        self.title("Select HubSpot Object and Properties")
        self.geometry("600x500")

        # Make modal
        self.transient(parent)
        self.grab_set()

        self._create_widgets()
        self._load_objects()

    def _create_widgets(self):
        """Create picker widgets."""
        # Object selection
        object_frame = ttk.LabelFrame(self, text="Select Object", padding=10)
        object_frame.pack(fill=tk.X, padx=20, pady=(20, 10))

        self.object_var = tk.StringVar()
        self.object_combo = ttk.Combobox(
            object_frame, textvariable=self.object_var, state="readonly", width=30
        )
        self.object_combo.pack(side=tk.LEFT, padx=(0, 10))
        self.object_combo.bind("<<ComboboxSelected>>", self._on_object_change)

        self.object_label = ttk.Label(object_frame, text="", foreground="gray")
        self.object_label.pack(side=tk.LEFT)

        # Property selection
        prop_frame = ttk.LabelFrame(self, text="Select Properties", padding=10)
        prop_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        # Search
        search_frame = ttk.Frame(prop_frame)
        search_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(search_frame, text="Search:").pack(side=tk.LEFT)
        self.search_var = tk.StringVar()
        self.search_var.trace("w", self._filter_properties)
        ttk.Entry(search_frame, textvariable=self.search_var, width=30).pack(
            side=tk.LEFT, padx=(5, 0)
        )

        # Property listbox with scrollbar
        list_frame = ttk.Frame(prop_frame)
        list_frame.pack(fill=tk.BOTH, expand=True)

        scrollbar = ttk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        self.property_listbox = tk.Listbox(
            list_frame, selectmode=tk.MULTIPLE, yscrollcommand=scrollbar.set
        )
        self.property_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.property_listbox.yview)

        # Quick select buttons
        quick_frame = ttk.Frame(prop_frame)
        quick_frame.pack(fill=tk.X, pady=(10, 0))

        ttk.Button(quick_frame, text="Select All", command=self._select_all).pack(
            side=tk.LEFT, padx=(0, 5)
        )

        ttk.Button(quick_frame, text="Select None", command=self._select_none).pack(
            side=tk.LEFT, padx=(0, 5)
        )

        ttk.Button(quick_frame, text="Select Common", command=self._select_common).pack(
            side=tk.LEFT
        )

        self.count_label = ttk.Label(quick_frame, text="0 selected")
        self.count_label.pack(side=tk.RIGHT)

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

        ttk.Button(button_frame, text="Cancel", command=self.destroy).pack(
            side=tk.RIGHT, padx=(5, 0)
        )

        ttk.Button(
            button_frame, text="OK", command=self._ok, style="Accent.TButton"
        ).pack(side=tk.RIGHT)

        # Status
        self.status_label = ttk.Label(button_frame, text="", foreground="blue")
        self.status_label.pack(side=tk.LEFT)

        # Bind selection change
        self.property_listbox.bind("<<ListboxSelect>>", self._update_count)

    def _load_objects(self):
        """Load HubSpot objects."""
        self.status_label.config(text="Loading objects...")
        self.after(100, self._fetch_objects)

    def _fetch_objects(self):
        """Fetch objects from API."""
        try:
            # Run async operation
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            objects = loop.run_until_complete(self.integration.get_objects())
            loop.close()

            # Populate combo
            object_names = [obj.name for obj in objects]
            self.object_combo["values"] = object_names

            if object_names:
                self.object_combo.set(object_names[0])
                self._on_object_change()

            self.status_label.config(text="")

        except Exception as e:
            logger.error(f"Error loading objects: {e}")
            messagebox.showerror("Error", f"Failed to load objects: {str(e)}")

    def _on_object_change(self, event=None):
        """Handle object selection change."""
        object_name = self.object_var.get()
        if not object_name:
            return

        self.selected_object = object_name
        self.object_label.config(text=f"Loading properties for {object_name}...")

        # Clear property list
        self.property_listbox.delete(0, tk.END)
        self.properties = []

        # Load properties
        self.after(100, lambda: self._fetch_properties(object_name))

    def _fetch_properties(self, object_name: str):
        """Fetch properties for object."""
        try:
            # Run async operation
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            properties = loop.run_until_complete(
                self.integration.get_object_properties(object_name)
            )
            loop.close()

            self.properties = properties
            self.all_properties = [(p.name, p.label) for p in properties]

            # Populate listbox
            for prop in properties:
                display_text = f"{prop.name} ({prop.label})"
                if prop.required:
                    display_text += " *"
                self.property_listbox.insert(tk.END, display_text)

            self.object_label.config(text=f"{len(properties)} properties")

        except Exception as e:
            logger.error(f"Error loading properties: {e}")
            self.object_label.config(text=f"Error: {str(e)}", foreground="red")

    def _filter_properties(self, *args):
        """Filter properties based on search."""
        search_term = self.search_var.get().lower()

        self.property_listbox.delete(0, tk.END)

        for i, prop in enumerate(self.properties):
            if search_term in prop.name.lower() or search_term in prop.label.lower():
                display_text = f"{prop.name} ({prop.label})"
                if prop.required:
                    display_text += " *"
                self.property_listbox.insert(tk.END, display_text)

    def _select_all(self):
        """Select all properties."""
        self.property_listbox.select_set(0, tk.END)
        self._update_count()

    def _select_none(self):
        """Deselect all properties."""
        self.property_listbox.select_clear(0, tk.END)
        self._update_count()

    def _select_common(self):
        """Select commonly used properties."""
        common_props = {
            "contacts": ["firstname", "lastname", "email", "phone", "company"],
            "companies": ["name", "domain", "phone", "city", "state", "country"],
            "deals": ["dealname", "amount", "dealstage", "closedate", "pipeline"],
        }

        object_common = common_props.get(self.selected_object, [])

        self.property_listbox.select_clear(0, tk.END)

        for i, prop in enumerate(self.properties):
            if prop.name in object_common:
                self.property_listbox.select_set(i)

        self._update_count()

    def _update_count(self, event=None):
        """Update selection count."""
        count = len(self.property_listbox.curselection())
        self.count_label.config(text=f"{count} selected")

    def _ok(self):
        """Handle OK button."""
        indices = self.property_listbox.curselection()
        self.selected_properties = [self.properties[i].name for i in indices]

        if not self.selected_properties:
            messagebox.showwarning("Warning", "Please select at least one property")
            return

        self.destroy()


class HubSpotWorkflowDialog(tk.Toplevel):
    """Dialog for configuring and running HubSpot workflows."""

    def __init__(
        self, parent, integration: HubSpotIntegration, workflow_type: str = "dedupe"
    ):
        super().__init__(parent)
        self.parent = parent
        self.integration = integration
        self.workflow_type = workflow_type
        self.workflow_engine = HubSpotWorkflowEngine(integration)

        self.title(f"HubSpot {workflow_type.title()} Workflow")
        self.geometry("700x600")

        # Make modal
        self.transient(parent)
        self.grab_set()

        self._create_widgets()

    def _create_widgets(self):
        """Create workflow dialog widgets."""
        # Create notebook for workflow steps
        self.notebook = ttk.Notebook(self)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # Configuration tab
        self.config_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.config_frame, text="Configuration")
        self._create_config_widgets()

        # Preview tab
        self.preview_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.preview_frame, text="Preview")
        self._create_preview_widgets()

        # Execute tab
        self.execute_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.execute_frame, text="Execute")
        self._create_execute_widgets()

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

        ttk.Button(button_frame, text="Close", command=self.destroy).pack(side=tk.RIGHT)

        self.next_button = ttk.Button(
            button_frame, text="Next ->", command=self._next_tab, style="Accent.TButton"
        )
        self.next_button.pack(side=tk.RIGHT, padx=(0, 5))

        self.back_button = ttk.Button(
            button_frame, text="<- Back", command=self._prev_tab, state="disabled"
        )
        self.back_button.pack(side=tk.RIGHT, padx=(0, 5))

        # Bind tab change
        self.notebook.bind("<<NotebookTabChanged>>", self._on_tab_change)

    def _create_config_widgets(self):
        """Create configuration widgets."""
        if self.workflow_type == "dedupe":
            # Object selection
            obj_frame = ttk.LabelFrame(self.config_frame, text="Object", padding=10)
            obj_frame.pack(fill=tk.X, padx=20, pady=(20, 10))

            self.object_var = tk.StringVar(value="contacts")
            ttk.Combobox(
                obj_frame,
                textvariable=self.object_var,
                values=["contacts", "companies", "deals"],
                state="readonly",
                width=30,
            ).pack(side=tk.LEFT)

            # Match fields
            match_frame = ttk.LabelFrame(
                self.config_frame, text="Match Fields", padding=10
            )
            match_frame.pack(fill=tk.X, padx=20, pady=10)

            self.match_fields_var = tk.StringVar(value="email")
            ttk.Entry(match_frame, textvariable=self.match_fields_var, width=40).pack()
            ttk.Label(
                match_frame,
                text="Comma-separated field names for matching duplicates",
                foreground="gray",
            ).pack()

            # Strategy
            strategy_frame = ttk.LabelFrame(
                self.config_frame, text="Merge Strategy", padding=10
            )
            strategy_frame.pack(fill=tk.X, padx=20, pady=10)

            self.strategy_var = tk.StringVar(value="most_complete")
            strategies = [
                ("Keep most complete record", "most_complete"),
                ("Keep newest record", "newest"),
                ("Keep oldest record", "oldest"),
            ]

            for text, value in strategies:
                ttk.Radiobutton(
                    strategy_frame, text=text, variable=self.strategy_var, value=value
                ).pack(anchor=tk.W)

        elif self.workflow_type == "association":
            # From/To objects
            obj_frame = ttk.LabelFrame(self.config_frame, text="Objects", padding=10)
            obj_frame.pack(fill=tk.X, padx=20, pady=(20, 10))

            ttk.Label(obj_frame, text="From:").grid(row=0, column=0, sticky=tk.W)
            self.from_object_var = tk.StringVar(value="contacts")
            ttk.Combobox(
                obj_frame,
                textvariable=self.from_object_var,
                values=["contacts", "companies", "deals"],
                state="readonly",
                width=20,
            ).grid(row=0, column=1, padx=(10, 20))

            ttk.Label(obj_frame, text="To:").grid(row=0, column=2, sticky=tk.W)
            self.to_object_var = tk.StringVar(value="companies")
            ttk.Combobox(
                obj_frame,
                textvariable=self.to_object_var,
                values=["contacts", "companies", "deals"],
                state="readonly",
                width=20,
            ).grid(row=0, column=3, padx=(10, 0))

            # Confidence threshold
            threshold_frame = ttk.LabelFrame(
                self.config_frame, text="Settings", padding=10
            )
            threshold_frame.pack(fill=tk.X, padx=20, pady=10)

            ttk.Label(threshold_frame, text="Confidence Threshold:").pack(side=tk.LEFT)
            self.threshold_var = tk.DoubleVar(value=0.80)
            ttk.Scale(
                threshold_frame,
                from_=0.0,
                to=1.0,
                variable=self.threshold_var,
                orient=tk.HORIZONTAL,
                length=200,
            ).pack(side=tk.LEFT, padx=(10, 10))
            self.threshold_label = ttk.Label(threshold_frame, text="0.80")
            self.threshold_label.pack(side=tk.LEFT)

            # Update label on scale change
            self.threshold_var.trace(
                "w",
                lambda *args: self.threshold_label.config(
                    text=f"{self.threshold_var.get():.2f}"
                ),
            )

    def _create_preview_widgets(self):
        """Create preview widgets."""
        # Preview text
        self.preview_text = tk.Text(self.preview_frame, wrap=tk.WORD, height=15)
        self.preview_text.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # Make read-only
        self.preview_text.config(state="disabled")

        # Preview button
        ttk.Button(
            self.preview_frame, text="Generate Preview", command=self._generate_preview
        ).pack(pady=(0, 20))

    def _create_execute_widgets(self):
        """Create execution widgets."""
        # Options
        options_frame = ttk.LabelFrame(
            self.execute_frame, text="Execution Options", padding=10
        )
        options_frame.pack(fill=tk.X, padx=20, pady=(20, 10))

        self.dry_run_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(
            options_frame,
            text="Dry run (preview changes without applying)",
            variable=self.dry_run_var,
        ).pack(anchor=tk.W)

        self.backup_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(
            options_frame,
            text="Create backup before execution",
            variable=self.backup_var,
        ).pack(anchor=tk.W)

        # Progress
        progress_frame = ttk.LabelFrame(self.execute_frame, text="Progress", padding=10)
        progress_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(
            progress_frame, variable=self.progress_var, maximum=100
        )
        self.progress_bar.pack(fill=tk.X, pady=(10, 5))

        self.progress_label = ttk.Label(progress_frame, text="Ready to execute")
        self.progress_label.pack()

        # Results text
        self.results_text = tk.Text(progress_frame, wrap=tk.WORD, height=10)
        self.results_text.pack(fill=tk.BOTH, expand=True, pady=(10, 0))

        # Execute button
        self.execute_button = ttk.Button(
            self.execute_frame,
            text="Execute Workflow",
            command=self._execute_workflow,
            style="Accent.TButton",
        )
        self.execute_button.pack(pady=(10, 20))

    def _next_tab(self):
        """Go to next tab."""
        current = self.notebook.index("current")
        if current < len(self.notebook.tabs()) - 1:
            self.notebook.select(current + 1)

    def _prev_tab(self):
        """Go to previous tab."""
        current = self.notebook.index("current")
        if current > 0:
            self.notebook.select(current - 1)

    def _on_tab_change(self, event=None):
        """Handle tab change."""
        current = self.notebook.index("current")

        # Update button states
        self.back_button.config(state="normal" if current > 0 else "disabled")
        self.next_button.config(
            state="normal" if current < len(self.notebook.tabs()) - 1 else "disabled"
        )

    def _generate_preview(self):
        """Generate workflow preview."""
        # This would actually load data and generate preview
        # For demo, just show sample preview
        preview_text = """
WORKFLOW PREVIEW
===============

Type: Contact Deduplication
Object: contacts
Match Fields: email
Strategy: Keep most complete record

ESTIMATED IMPACT:
- Total records to process: 1,234
- Duplicate groups found: 56
- Records to be merged: 112
- Estimated API calls: 112
- Estimated duration: ~2 minutes

SAMPLE DUPLICATES:
1. john.doe@example.com (3 duplicates)
   - Record 1: John Doe (created: 2023-01-15)
   - Record 2: John D. (created: 2023-03-20)
   - Record 3: J. Doe (created: 2023-06-10)
   -> Will keep Record 1 (most complete)

2. jane.smith@example.com (2 duplicates)
   - Record 1: Jane Smith (created: 2023-02-01)
   - Record 2: Jane S. (created: 2023-04-15)
   -> Will keep Record 1 (most complete)

API LIMITS CHECK:
- Current remaining: 145/150 requests per 10 seconds
- Daily remaining: 45,231/50,000 requests
- Sufficient capacity: ✓ Yes
"""

        self.preview_text.config(state="normal")
        self.preview_text.delete(1.0, tk.END)
        self.preview_text.insert(1.0, preview_text)
        self.preview_text.config(state="disabled")

    def _execute_workflow(self):
        """Execute the workflow."""
        self.execute_button.config(state="disabled")
        self.progress_var.set(0)
        self.progress_label.config(text="Starting workflow...")

        # Clear results
        self.results_text.delete(1.0, tk.END)

        # In real implementation, this would run the actual workflow
        # For demo, simulate progress
        self._simulate_execution()

    def _simulate_execution(self):
        """Simulate workflow execution."""
        steps = [
            (10, "Loading data..."),
            (25, "Validating records..."),
            (40, "Finding duplicates..."),
            (60, "Creating backup..."),
            (80, "Merging duplicates..."),
            (100, "Workflow completed!"),
        ]

        def update_step(index=0):
            if index < len(steps):
                progress, message = steps[index]
                self.progress_var.set(progress)
                self.progress_label.config(text=message)

                # Add to results
                self.results_text.insert(tk.END, f"[{progress}%] {message}\n")
                self.results_text.see(tk.END)

                # Schedule next step
                self.after(1000, lambda: update_step(index + 1))
            else:
                # Complete
                self.execute_button.config(state="normal")
                self.results_text.insert(tk.END, "\n" + "=" * 50 + "\n")
                self.results_text.insert(tk.END, "RESULTS:\n")
                self.results_text.insert(tk.END, "- Records processed: 1,234\n")
                self.results_text.insert(tk.END, "- Duplicates merged: 112\n")
                self.results_text.insert(tk.END, "- Errors: 0\n")
                self.results_text.insert(tk.END, "- Duration: 1m 47s\n")
                self.results_text.see(tk.END)

        update_step()


def show_hubspot_connection_dialog(parent) -> Optional[HubSpotCredentials]:
    """Show HubSpot connection dialog and return credentials."""
    dialog = HubSpotConnectionDialog(parent)
    parent.wait_window(dialog)
    return dialog.result


def show_hubspot_object_picker(
    parent, integration: HubSpotIntegration
) -> Optional[Tuple[str, List[str]]]:
    """Show object/property picker and return selection."""
    dialog = HubSpotObjectPicker(parent, integration)
    parent.wait_window(dialog)

    if dialog.selected_object and dialog.selected_properties:
        return dialog.selected_object, dialog.selected_properties
    return None


def show_hubspot_workflow_dialog(
    parent, integration: HubSpotIntegration, workflow_type: str = "dedupe"
):
    """Show workflow configuration and execution dialog."""
    dialog = HubSpotWorkflowDialog(parent, integration, workflow_type)
    parent.wait_window(dialog)


def show_hubspot_api_limits(parent, limits: ApiLimits):
    """Show current API limits in a dialog."""
    dialog = tk.Toplevel(parent)
    dialog.title("HubSpot API Limits")
    dialog.geometry("400x300")
    dialog.transient(parent)
    dialog.grab_set()

    # Header
    ttk.Label(dialog, text="Current API Usage", font=("Arial", 14, "bold")).pack(
        pady=(20, 10)
    )

    # Limits frame
    limits_frame = ttk.Frame(dialog)
    limits_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

    # Core API
    core_frame = ttk.LabelFrame(
        limits_frame, text="Core API (per 10 seconds)", padding=10
    )
    core_frame.pack(fill=tk.X, pady=(0, 10))

    ttk.Label(
        core_frame, text=f"Remaining: {limits.core_api_remaining}/{limits.core_api_max}"
    ).pack(anchor=tk.W)

    core_progress = ttk.Progressbar(
        core_frame, maximum=limits.core_api_max, value=limits.core_api_remaining
    )
    core_progress.pack(fill=tk.X, pady=(5, 0))

    # Daily limits
    if limits.daily_max:
        daily_frame = ttk.LabelFrame(limits_frame, text="Daily Limits", padding=10)
        daily_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(
            daily_frame,
            text=f"Remaining: {limits.daily_remaining:,}/{limits.daily_max:,}",
        ).pack(anchor=tk.W)

        daily_progress = ttk.Progressbar(
            daily_frame, maximum=limits.daily_max, value=limits.daily_remaining or 0
        )
        daily_progress.pack(fill=tk.X, pady=(5, 0))

    # Close button
    ttk.Button(dialog, text="Close", command=dialog.destroy).pack(pady=(0, 20))

    # Center dialog
    dialog.update_idletasks()
    x = (dialog.winfo_screenwidth() - dialog.winfo_width()) // 2
    y = (dialog.winfo_screenheight() - dialog.winfo_height()) // 2
    dialog.geometry(f"+{x}+{y}")


# Integration helpers for main GUI
def add_hubspot_menu_items(menu_bar, main_window):
    """Add HubSpot menu items to the main application menu."""
    hubspot_menu = tk.Menu(menu_bar, tearoff=0)
    menu_bar.add_cascade(label="HubSpot", menu=hubspot_menu)

    hubspot_menu.add_command(
        label="Connect to HubSpot...",
        command=lambda: _handle_hubspot_connect(main_window),
    )

    hubspot_menu.add_separator()

    hubspot_menu.add_command(
        label="Import from HubSpot...",
        command=lambda: _handle_hubspot_import(main_window),
    )

    hubspot_menu.add_command(
        label="Export to HubSpot...",
        command=lambda: _handle_hubspot_export(main_window),
    )

    hubspot_menu.add_separator()

    hubspot_menu.add_command(
        label="Deduplicate Records...",
        command=lambda: _handle_hubspot_dedupe(main_window),
    )

    hubspot_menu.add_command(
        label="Create Associations...",
        command=lambda: _handle_hubspot_associations(main_window),
    )

    hubspot_menu.add_separator()

    hubspot_menu.add_command(
        label="View API Limits...", command=lambda: _handle_view_limits(main_window)
    )


def _handle_hubspot_connect(main_window):
    """Handle HubSpot connection menu item."""
    credentials = show_hubspot_connection_dialog(main_window)
    if credentials:
        # Store credentials in main window
        main_window.hubspot_credentials = credentials
        messagebox.showinfo("Success", "Connected to HubSpot successfully!")


def _handle_hubspot_import(main_window):
    """Handle HubSpot import menu item."""
    if not hasattr(main_window, "hubspot_credentials"):
        messagebox.showwarning("Not Connected", "Please connect to HubSpot first")
        return

    # Would implement actual import logic here
    messagebox.showinfo(
        "Import", "HubSpot import functionality would be implemented here"
    )


def _handle_hubspot_export(main_window):
    """Handle HubSpot export menu item."""
    if not hasattr(main_window, "hubspot_credentials"):
        messagebox.showwarning("Not Connected", "Please connect to HubSpot first")
        return

    # Would implement actual export logic here
    messagebox.showinfo(
        "Export", "HubSpot export functionality would be implemented here"
    )


def _handle_hubspot_dedupe(main_window):
    """Handle deduplication workflow."""
    if not hasattr(main_window, "hubspot_credentials"):
        messagebox.showwarning("Not Connected", "Please connect to HubSpot first")
        return

    # Create integration instance
    integration = HubSpotIntegration(main_window.hubspot_credentials)

    # Show workflow dialog
    show_hubspot_workflow_dialog(main_window, integration, "dedupe")


def _handle_hubspot_associations(main_window):
    """Handle association workflow."""
    if not hasattr(main_window, "hubspot_credentials"):
        messagebox.showwarning("Not Connected", "Please connect to HubSpot first")
        return

    # Create integration instance
    integration = HubSpotIntegration(main_window.hubspot_credentials)

    # Show workflow dialog
    show_hubspot_workflow_dialog(main_window, integration, "association")


def _handle_view_limits(main_window):
    """Handle view API limits."""
    if not hasattr(main_window, "hubspot_credentials"):
        messagebox.showwarning("Not Connected", "Please connect to HubSpot first")
        return

    # Create integration instance
    integration = HubSpotIntegration(main_window.hubspot_credentials)

    # Show limits dialog
    show_hubspot_api_limits(main_window, integration.api_limits)


# Additional helper functions for main GUI integration


def add_hubspot_toolbar_buttons(toolbar, main_window):
    """Add HubSpot-specific buttons to the main toolbar."""
    # Add separator
    ttk.Separator(toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, padx=5)

    # HubSpot connection status
    main_window.hubspot_status_label = ttk.Label(
        toolbar, text="HubSpot: Not Connected", foreground="gray"
    )
    main_window.hubspot_status_label.pack(side=tk.LEFT, padx=(0, 10))

    # Quick connect button
    ttk.Button(
        toolbar,
        text="Connect HubSpot",
        command=lambda: _handle_hubspot_connect(main_window),
    ).pack(side=tk.LEFT)


def update_hubspot_status(main_window, connected: bool = False):
    """Update HubSpot connection status in toolbar."""
    if hasattr(main_window, "hubspot_status_label"):
        if connected and hasattr(main_window, "hubspot_credentials"):
            creds = main_window.hubspot_credentials
            status_text = f"HubSpot: Connected ({creds.portal_id or 'Portal'})"
            main_window.hubspot_status_label.config(
                text=status_text, foreground="green"
            )
        else:
            main_window.hubspot_status_label.config(
                text="HubSpot: Not Connected", foreground="gray"
            )


class HubSpotImportWizard(tk.Toplevel):
    """Wizard for importing data from HubSpot."""

    def __init__(self, parent, integration: HubSpotIntegration):
        super().__init__(parent)
        self.parent = parent
        self.integration = integration
        self.selected_data = None

        self.title("Import from HubSpot")
        self.geometry("800x600")

        # Make modal
        self.transient(parent)
        self.grab_set()

        self._create_widgets()

    def _create_widgets(self):
        """Create import wizard widgets."""
        # Create notebook for steps
        self.notebook = ttk.Notebook(self)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # Step 1: Select object and properties
        self.select_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.select_frame, text="1. Select Data")
        self._create_select_widgets()

        # Step 2: Filter and preview
        self.filter_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.filter_frame, text="2. Filter & Preview")
        self._create_filter_widgets()

        # Step 3: Import
        self.import_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.import_frame, text="3. Import")
        self._create_import_widgets()

        # Navigation buttons
        button_frame = ttk.Frame(self)
        button_frame.pack(fill=tk.X, padx=20, pady=(0, 20))

        ttk.Button(button_frame, text="Cancel", command=self.destroy).pack(
            side=tk.RIGHT, padx=(5, 0)
        )

        self.next_button = ttk.Button(
            button_frame,
            text="Next ->",
            command=self._next_step,
            style="Accent.TButton",
        )
        self.next_button.pack(side=tk.RIGHT)

        self.back_button = ttk.Button(
            button_frame, text="<- Back", command=self._prev_step, state="disabled"
        )
        self.back_button.pack(side=tk.RIGHT, padx=(0, 5))

    def _create_select_widgets(self):
        """Create object/property selection widgets."""
        # Instructions
        ttk.Label(
            self.select_frame,
            text="Select the HubSpot object type and properties to import:",
            font=("Arial", 10),
        ).pack(pady=(20, 10))

        # Object selection
        obj_frame = ttk.LabelFrame(self.select_frame, text="Object Type", padding=10)
        obj_frame.pack(fill=tk.X, padx=20, pady=10)

        self.object_var = tk.StringVar()
        self.object_combo = ttk.Combobox(
            obj_frame, textvariable=self.object_var, state="readonly", width=30
        )
        self.object_combo.pack()

        # Property selection placeholder
        prop_frame = ttk.LabelFrame(self.select_frame, text="Properties", padding=10)
        prop_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        ttk.Label(
            prop_frame,
            text="Select an object type first to see available properties",
            foreground="gray",
        ).pack(expand=True)

    def _create_filter_widgets(self):
        """Create filter and preview widgets."""
        # Filter options
        filter_frame = ttk.LabelFrame(self.filter_frame, text="Filters", padding=10)
        filter_frame.pack(fill=tk.X, padx=20, pady=(20, 10))

        ttk.Label(filter_frame, text="Date range:").grid(row=0, column=0, sticky=tk.W)
        self.date_filter_var = tk.StringVar(value="all")
        ttk.Combobox(
            filter_frame,
            textvariable=self.date_filter_var,
            values=["all", "last_7_days", "last_30_days", "last_90_days", "custom"],
            state="readonly",
            width=20,
        ).grid(row=0, column=1, padx=(10, 0))

        # Preview area
        preview_frame = ttk.LabelFrame(
            self.filter_frame, text="Data Preview", padding=10
        )
        preview_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        # Preview table would go here
        self.preview_text = tk.Text(preview_frame, height=10)
        self.preview_text.pack(fill=tk.BOTH, expand=True)

    def _create_import_widgets(self):
        """Create import execution widgets."""
        # Import options
        options_frame = ttk.LabelFrame(
            self.import_frame, text="Import Options", padding=10
        )
        options_frame.pack(fill=tk.X, padx=20, pady=(20, 10))

        self.update_existing_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(
            options_frame,
            text="Update existing records in FuzzyMatcher",
            variable=self.update_existing_var,
        ).pack(anchor=tk.W)

        # Progress area
        progress_frame = ttk.LabelFrame(
            self.import_frame, text="Import Progress", padding=10
        )
        progress_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)

        self.import_progress = ttk.Progressbar(progress_frame)
        self.import_progress.pack(fill=tk.X, pady=(10, 5))

        self.import_status = ttk.Label(progress_frame, text="Ready to import")
        self.import_status.pack()

        # Import button
        self.import_button = ttk.Button(
            progress_frame,
            text="Start Import",
            command=self._start_import,
            style="Accent.TButton",
        )
        self.import_button.pack(pady=20)

    def _next_step(self):
        """Move to next step in wizard."""
        current = self.notebook.index("current")
        if current < len(self.notebook.tabs()) - 1:
            self.notebook.select(current + 1)
            self._update_navigation()

    def _prev_step(self):
        """Move to previous step in wizard."""
        current = self.notebook.index("current")
        if current > 0:
            self.notebook.select(current - 1)
            self._update_navigation()

    def _update_navigation(self):
        """Update navigation button states."""
        current = self.notebook.index("current")
        total = len(self.notebook.tabs())

        self.back_button.config(state="normal" if current > 0 else "disabled")
        self.next_button.config(state="normal" if current < total - 1 else "disabled")

    def _start_import(self):
        """Start the import process."""
        self.import_button.config(state="disabled")
        self.import_status.config(text="Import in progress...")
        # Implementation would follow here


# Export functions for use by main application
__all__ = [
    "HubSpotConnectionDialog",
    "HubSpotObjectPicker",
    "HubSpotWorkflowDialog",
    "HubSpotImportWizard",
    "show_hubspot_connection_dialog",
    "show_hubspot_object_picker",
    "show_hubspot_workflow_dialog",
    "show_hubspot_api_limits",
    "add_hubspot_menu_items",
    "add_hubspot_toolbar_buttons",
    "update_hubspot_status",
]
