"""
Salesforce Workflows Module for FoundryMatch
============================================
Implements Salesforce-specific workflows including deduplication and Lead-to-Account matching
with comprehensive safety controls and audit trails.
"""

import re
import logging
import tempfile
import uuid
from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict, List, Optional, Any
import pandas as pd

from .core import SalesforceIntegration

log = logging.getLogger(__name__)


@dataclass
class WorkflowConfig:
    """Base configuration for Salesforce workflows."""

    workflow_id: str = field(default_factory=lambda: str(uuid.uuid4()))
    created_at: datetime = field(default_factory=datetime.now)
    dry_run: bool = True
    backup_enabled: bool = True
    audit_enabled: bool = True
    api_limit_check: bool = True
    max_records_per_batch: int = 200
    estimated_api_calls: int = 0


@dataclass
class DedupeWorkflowConfig(WorkflowConfig):
    """Configuration for Salesforce deduplication workflow."""

    object_name: str = ""
    master_record_strategy: str = "oldest"  # oldest, newest, most_complete
    fields_to_merge: List[str] = field(default_factory=list)
    delete_duplicates: bool = False  # Use merge instead of delete
    preserve_activities: bool = True
    preserve_notes: bool = True


@dataclass
class LeadToAccountConfig(WorkflowConfig):
    """Configuration for Lead-to-Account matching workflow."""

    target_lookup_field: str = "AccountId"
    secondary_lookup_field: Optional[str] = None
    create_account_if_no_match: bool = False
    match_confidence_threshold: float = 85.0
    update_lead_status: bool = True
    new_lead_status: str = "Qualified"


@dataclass
class WorkflowResult:
    """Result of a workflow execution."""

    workflow_id: str
    success: bool
    records_processed: int = 0
    records_updated: int = 0
    records_created: int = 0
    records_merged: int = 0
    api_calls_used: int = 0
    execution_time: float = 0.0
    error_message: Optional[str] = None
    backup_file: Optional[str] = None
    audit_log: List[Dict[str, Any]] = field(default_factory=list)


@dataclass
class PreviewResult:
    """Result of a workflow preview."""

    workflow_id: str
    total_candidates: int
    estimated_updates: int
    estimated_api_calls: int
    confidence_distribution: Dict[str, int]
    sample_matches: List[Dict[str, Any]]
    potential_issues: List[str]


class SalesforceWorkflowEngine:
    """Engine for executing Salesforce-specific workflows with safety controls."""

    def __init__(self, sf_integration: SalesforceIntegration):
        self.sf_integration = sf_integration
        self.active_workflows: Dict[str, WorkflowConfig] = {}
        self.audit_logs: Dict[str, List[Dict[str, Any]]] = {}

    async def preview_dedupe_workflow(
        self, config: DedupeWorkflowConfig, matches_df: pd.DataFrame
    ) -> PreviewResult:
        """
        Preview deduplication workflow without making changes.

        Args:
            config: Deduplication configuration
            matches_df: DataFrame with match results from FoundryMatch engine

        Returns:
            PreviewResult with analysis of planned changes
        """
        try:
            log.info(f"Starting deduplication preview for {config.object_name}")

            # Analyze matches for preview
            total_candidates = len(matches_df)
            estimated_updates = 0
            confidence_dist = {"High (90%+)": 0, "Medium (75-89%)": 0, "Low (< 75%)": 0}
            sample_matches = []
            potential_issues = []

            # Group by master record (assuming first record is master)
            grouped_matches = self._group_matches_by_master(matches_df)

            for master_id, duplicate_group in grouped_matches.items():
                if len(duplicate_group) > 1:
                    estimated_updates += len(duplicate_group) - 1  # All except master

                    # Analyze confidence distribution
                    for _, match in duplicate_group.iterrows():
                        confidence = match.get("confidence_score", 0)
                        if confidence >= 90:
                            confidence_dist["High (90%+)"] += 1
                        elif confidence >= 75:
                            confidence_dist["Medium (75-89%)"] += 1
                        else:
                            confidence_dist["Low (< 75%)"] += 1

                    # Add to sample matches (first 10)
                    if len(sample_matches) < 10:
                        sample_matches.append(
                            {
                                "master_id": master_id,
                                "duplicate_ids": [
                                    dup["Id"]
                                    for _, dup in duplicate_group.iterrows()
                                    if dup["Id"] != master_id
                                ],
                                "confidence_scores": [
                                    dup.get("confidence_score", 0)
                                    for _, dup in duplicate_group.iterrows()
                                ],
                                "master_name": duplicate_group.iloc[0].get(
                                    "Name", "Unknown"
                                ),
                            }
                        )

            # Estimate API calls
            estimated_merges = len(grouped_matches)
            config.estimated_api_calls = (
                estimated_merges * 1
            )  # 1 call per merge operation

            # Check for potential issues
            if config.estimated_api_calls > 1000:
                potential_issues.append(
                    f"High API usage: {config.estimated_api_calls} calls estimated"
                )

            # Check API limits
            limits = await self.sf_integration.get_api_limits()
            if limits:
                remaining_calls = (
                    limits.daily_api_requests_max - limits.daily_api_requests_used
                )
                if config.estimated_api_calls > remaining_calls * 0.8:
                    potential_issues.append(
                        f"May exceed API limits (need {config.estimated_api_calls}, have {remaining_calls})"
                    )

            # Check for large merge groups
            large_groups = [
                group for group in grouped_matches.values() if len(group) > 10
            ]
            if large_groups:
                potential_issues.append(
                    f"Found {len(large_groups)} merge groups with >10 records"
                )

            return PreviewResult(
                workflow_id=config.workflow_id,
                total_candidates=total_candidates,
                estimated_updates=estimated_updates,
                estimated_api_calls=config.estimated_api_calls,
                confidence_distribution=confidence_dist,
                sample_matches=sample_matches,
                potential_issues=potential_issues,
            )

        except Exception as e:
            log.error(f"Error previewing dedupe workflow: {e}", exc_info=True)
            raise

    async def execute_dedupe_workflow(
        self,
        config: DedupeWorkflowConfig,
        matches_df: pd.DataFrame,
        progress_callback=None,
    ) -> WorkflowResult:
        """
        Execute deduplication workflow with full safety controls.

        Args:
            config: Deduplication configuration
            matches_df: DataFrame with match results
            progress_callback: Optional progress callback function

        Returns:
            WorkflowResult with execution details
        """
        start_time = datetime.now()
        result = WorkflowResult(workflow_id=config.workflow_id, success=False)

        try:
            log.info(f"Starting deduplication workflow {config.workflow_id}")

            # Store active workflow
            self.active_workflows[config.workflow_id] = config

            # Pre-execution safety checks
            if not await self._pre_execution_checks(config):
                result.error_message = "Pre-execution safety checks failed"
                return result

            # Create backup if enabled
            backup_file = None
            if config.backup_enabled:
                backup_file = await self._create_backup(config.object_name, matches_df)
                result.backup_file = backup_file

            # Group matches by master record
            grouped_matches = self._group_matches_by_master(matches_df)
            total_groups = len(grouped_matches)
            processed_groups = 0

            if progress_callback:
                await progress_callback(
                    f"Processing {total_groups} duplicate groups", 0
                )

            # Process in batches
            batch_size = config.max_records_per_batch
            api_calls_used = 0
            records_merged = 0

            for i, (master_id, duplicate_group) in enumerate(grouped_matches.items()):
                if len(duplicate_group) <= 1:
                    continue  # Skip single records

                try:
                    # Perform merge operation
                    if not config.dry_run:
                        # Get all duplicate IDs for this master
                        duplicate_ids = [
                            dup["Id"]
                            for _, dup in duplicate_group.iterrows()
                            if dup["Id"] != master_id
                        ]

                        # Batch merge operations since API limit is 2 duplicates per call
                        batch_size = 2
                        for i_batch in range(0, len(duplicate_ids), batch_size):
                            id_batch = duplicate_ids[i_batch : i_batch + batch_size]

                            if not id_batch:
                                continue

                            merge_result = await self._merge_records(
                                config.object_name, master_id, id_batch, config
                            )

                            if merge_result["success"]:
                                records_merged += len(id_batch)
                                api_calls_used += 1

                            # Add to audit log for this batch
                            self._add_audit_entry(
                                config.workflow_id,
                                {
                                    "action": "merge_records",
                                    "master_id": master_id,
                                    "duplicate_ids": id_batch,
                                    "success": merge_result["success"],
                                    "timestamp": datetime.now().isoformat(),
                                },
                            )

                    processed_groups += 1

                    # Update progress
                    if progress_callback:
                        progress_pct = (processed_groups / total_groups) * 100
                        await progress_callback(
                            f"Processed {processed_groups}/{total_groups} groups",
                            progress_pct,
                        )

                    # Batch size check (for API limits)
                    if processed_groups % batch_size == 0:
                        # Check API limits
                        current_limits = await self.sf_integration.get_api_limits()
                        if current_limits and current_limits.is_near_limit():
                            log.warning("Approaching API limits, pausing workflow")
                            break

                except Exception as e:
                    log.error(f"Error processing group {master_id}: {e}", exc_info=True)
                    self._add_audit_entry(
                        config.workflow_id,
                        {
                            "action": "merge_records",
                            "master_id": master_id,
                            "error": str(e),
                            "timestamp": datetime.now().isoformat(),
                        },
                    )

            # Calculate final results
            execution_time = (datetime.now() - start_time).total_seconds()

            result.success = True
            result.records_processed = len(matches_df)
            result.records_merged = records_merged
            result.api_calls_used = api_calls_used
            result.execution_time = execution_time
            result.audit_log = self.audit_logs.get(config.workflow_id, [])

            log.info(
                f"Deduplication workflow completed: {records_merged} records merged"
            )

        except Exception as e:
            log.error(f"Error in deduplication workflow: {e}", exc_info=True)
            result.error_message = str(e)

        finally:
            # Cleanup
            if config.workflow_id in self.active_workflows:
                del self.active_workflows[config.workflow_id]

        return result

    async def preview_lead_to_account_workflow(
        self, config: LeadToAccountConfig, matches_df: pd.DataFrame
    ) -> PreviewResult:
        """Preview Lead-to-Account matching workflow."""
        try:
            log.info("Starting Lead-to-Account preview")

            total_candidates = len(matches_df)
            estimated_updates = 0
            confidence_dist = {"High (90%+)": 0, "Medium (75-89%)": 0, "Low (< 75%)": 0}
            sample_matches = []
            potential_issues = []

            # Analyze matches
            for _, match in matches_df.iterrows():
                confidence = match.get("confidence_score", 0)

                if confidence >= config.match_confidence_threshold:
                    estimated_updates += 1

                    # Confidence distribution
                    if confidence >= 90:
                        confidence_dist["High (90%+)"] += 1
                    elif confidence >= 75:
                        confidence_dist["Medium (75-89%)"] += 1
                    else:
                        confidence_dist["Low (< 75%)"] += 1

                    # Sample matches
                    if len(sample_matches) < 10:
                        sample_matches.append(
                            {
                                "lead_id": match.get("s_Id", "Unknown"),
                                "lead_name": match.get("s_Name", "Unknown"),
                                "account_id": match.get("r_Id", "Unknown"),
                                "account_name": match.get("r_Name", "Unknown"),
                                "confidence": confidence,
                            }
                        )

            # Estimate API calls (1 update per lead)
            config.estimated_api_calls = estimated_updates

            # Check for issues
            if config.estimated_api_calls > 5000:
                potential_issues.append(
                    f"Large batch: {config.estimated_api_calls} Lead updates"
                )

            # Check for leads that already have accounts
            leads_with_accounts = matches_df[matches_df["s_AccountId"].notna()]
            if not leads_with_accounts.empty:
                potential_issues.append(
                    f"{len(leads_with_accounts)} leads already have Account associations"
                )

            return PreviewResult(
                workflow_id=config.workflow_id,
                total_candidates=total_candidates,
                estimated_updates=estimated_updates,
                estimated_api_calls=config.estimated_api_calls,
                confidence_distribution=confidence_dist,
                sample_matches=sample_matches,
                potential_issues=potential_issues,
            )

        except Exception as e:
            log.error(f"Error previewing Lead-to-Account workflow: {e}", exc_info=True)
            raise

    async def execute_lead_to_account_workflow(
        self,
        config: LeadToAccountConfig,
        matches_df: pd.DataFrame,
        progress_callback=None,
    ) -> WorkflowResult:
        """Execute Lead-to-Account matching workflow."""
        start_time = datetime.now()
        result = WorkflowResult(workflow_id=config.workflow_id, success=False)

        try:
            log.info(f"Starting Lead-to-Account workflow {config.workflow_id}")

            self.active_workflows[config.workflow_id] = config

            # Pre-execution checks
            if not await self._pre_execution_checks(config):
                result.error_message = "Pre-execution safety checks failed"
                return result

            # Create backup
            backup_file = None
            if config.backup_enabled:
                backup_file = await self._create_backup("Lead", matches_df)
                result.backup_file = backup_file

            # Filter matches by confidence threshold
            qualified_matches = matches_df[
                matches_df["confidence_score"] >= config.match_confidence_threshold
            ]

            total_matches = len(qualified_matches)
            processed_matches = 0
            records_updated = 0
            api_calls_used = 0

            if progress_callback:
                await progress_callback(
                    f"Processing {total_matches} Lead-to-Account matches", 0
                )

            # Process in batches using Composite Graph
            batch_size = min(config.max_records_per_batch, 500)  # Composite Graph limit

            for i in range(0, total_matches, batch_size):
                batch = qualified_matches.iloc[i : i + batch_size]

                try:
                    if not config.dry_run:
                        # Prepare composite request
                        composite_request = self._build_lead_update_composite_request(
                            batch, config
                        )

                        # Execute composite update
                        composite_result = await self._execute_composite_request(
                            composite_request
                        )

                        if composite_result["success"]:
                            records_updated += len(batch)
                            api_calls_used += 1  # Composite Graph counts as 1 API call

                        # Audit each update
                        for _, match in batch.iterrows():
                            self._add_audit_entry(
                                config.workflow_id,
                                {
                                    "action": "update_lead_account",
                                    "lead_id": match["s_Id"],
                                    "account_id": match["r_Id"],
                                    "confidence": match["confidence_score"],
                                    "timestamp": datetime.now().isoformat(),
                                },
                            )

                    processed_matches += len(batch)

                    # Update progress
                    if progress_callback:
                        progress_pct = (processed_matches / total_matches) * 100
                        await progress_callback(
                            f"Updated {processed_matches}/{total_matches} leads",
                            progress_pct,
                        )

                except Exception as e:
                    log.error(f"Error processing Lead batch: {e}", exc_info=True)

            # Final results
            execution_time = (datetime.now() - start_time).total_seconds()

            result.success = True
            result.records_processed = total_matches
            result.records_updated = records_updated
            result.api_calls_used = api_calls_used
            result.execution_time = execution_time
            result.audit_log = self.audit_logs.get(config.workflow_id, [])

            log.info(
                f"Lead-to-Account workflow completed: {records_updated} leads updated"
            )

        except Exception as e:
            log.error(f"Error in Lead-to-Account workflow: {e}", exc_info=True)
            result.error_message = str(e)

        finally:
            if config.workflow_id in self.active_workflows:
                del self.active_workflows[config.workflow_id]

        return result

    def _group_matches_by_master(
        self, matches_df: pd.DataFrame
    ) -> Dict[str, pd.DataFrame]:
        """Group duplicate matches by master record."""
        grouped = {}

        # Assuming source ID is the master and reference IDs are duplicates
        # This logic would need to be adjusted based on your match results format
        for _, match in matches_df.iterrows():
            master_id = match.get("s_Id")  # Source ID as master
            if master_id not in grouped:
                grouped[master_id] = pd.DataFrame()

            # Add this match to the group
            grouped[master_id] = pd.concat(
                [grouped[master_id], match.to_frame().T], ignore_index=True
            )

        return grouped

    async def _merge_records(
        self,
        object_name: str,
        master_id: str,
        duplicate_ids: List[str],
        config: DedupeWorkflowConfig,
    ) -> Dict[str, Any]:
        """Merge duplicate records using Salesforce Merge API."""
        try:
            # Build merge request
            merge_url = f"{self.sf_integration.credentials.instance_url}/services/data/v59.0/sobjects/{object_name}/merge"

            merge_data = {
                "masterRecord": {"Id": master_id},
                "recordToMergeIds": duplicate_ids,
            }

            headers = {
                "Authorization": f"Bearer {self.sf_integration.credentials.access_token}",
                "Content-Type": "application/json",
            }

            response = await self.sf_integration._execute_api_request(
                "POST", merge_url, json=merge_data, headers=headers
            )

            return {
                "success": response.status_code == 200,
                "response": response.json() if response.content else {},
            }

        except Exception as e:
            log.error(f"Error merging records: {e}", exc_info=True)
            return {"success": False, "error": str(e)}

    def _build_lead_update_composite_request(
        self, batch_df: pd.DataFrame, config: LeadToAccountConfig
    ) -> Dict[str, Any]:
        """Build Composite Graph request for Lead updates."""
        composite_request = {
            "graphs": [
                {"graphId": f"LeadUpdate_{config.workflow_id}", "compositeRequest": []}
            ]
        }

        for i, (_, match) in enumerate(batch_df.iterrows()):
            update_data = {config.target_lookup_field: match["r_Id"]}

            # Add secondary lookup if configured
            if config.secondary_lookup_field:
                update_data[config.secondary_lookup_field] = match.get("r_parent_Id")

            # Update status if configured
            if config.update_lead_status:
                update_data["Status"] = config.new_lead_status

            # Add traceability field
            update_data["Matched_By_FoundryMatch__c"] = True
            update_data["Match_Confidence__c"] = match["confidence_score"]
            update_data["Match_Date__c"] = datetime.now().isoformat()

            composite_request["graphs"][0]["compositeRequest"].append(
                {
                    "method": "PATCH",
                    "url": f"/services/data/v59.0/sobjects/Lead/{match['s_Id']}",
                    "referenceId": f"lead_update_{i}",
                    "body": update_data,
                }
            )

        return composite_request

    async def _execute_composite_request(
        self, composite_request: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Execute Composite Graph request."""
        try:
            composite_url = f"{self.sf_integration.credentials.instance_url}/services/data/v59.0/composite/graph"

            headers = {
                "Authorization": f"Bearer {self.sf_integration.credentials.access_token}",
                "Content-Type": "application/json",
            }

            response = await self.sf_integration._execute_api_request(
                "POST", composite_url, json=composite_request, headers=headers
            )

            return {
                "success": response.status_code == 200,
                "response": response.json() if response.content else {},
            }

        except Exception as e:
            log.error(f"Error executing composite request: {e}", exc_info=True)
            return {"success": False, "error": str(e)}

    async def _pre_execution_checks(self, config: WorkflowConfig) -> bool:
        """Perform pre-execution safety checks."""
        try:
            # Check connection
            if not self.sf_integration.is_connected():
                log.error("Salesforce connection not available")
                return False

            # Check API limits
            if config.api_limit_check:
                limits = await self.sf_integration.get_api_limits()
                if limits:
                    remaining_calls = (
                        limits.daily_api_requests_max - limits.daily_api_requests_used
                    )
                    if config.estimated_api_calls > remaining_calls * 0.9:
                        log.error(
                            f"Insufficient API calls: need {config.estimated_api_calls}, have {remaining_calls}"
                        )
                        return False

            # Verify object permissions (would need additional API calls)
            # This is a placeholder for more comprehensive permission checks

            return True

        except Exception as e:
            log.error(f"Pre-execution check failed: {e}", exc_info=True)
            return False

    async def _create_backup(
        self, object_name: str, matches_df: pd.DataFrame
    ) -> Optional[str]:
        """Create backup of records before modification."""
        try:
            # Extract unique record IDs
            record_ids = set()
            for _, match in matches_df.iterrows():
                if "s_Id" in match and pd.notna(match["s_Id"]):
                    record_ids.add(match["s_Id"])
                if "r_Id" in match and pd.notna(match["r_Id"]):
                    record_ids.add(match["r_Id"])

            if not record_ids:
                log.warning("No record IDs found for backup")
                return None

            # Convert to list for batching
            record_ids_list = list(record_ids)
            all_backup_dfs = []
            batch_size = (
                2000  # Use a larger, more efficient batch size for SOQL IN clauses
            )

            log.info(
                f"Creating backup for {len(record_ids_list)} records in batches of {batch_size}"
            )

            # Process IDs in batches to avoid SOQL limits
            for i in range(0, len(record_ids_list), batch_size):
                # Get current batch of IDs
                id_batch = record_ids_list[i : i + batch_size]

                # Sanitize IDs to prevent SOQL injection. Salesforce IDs are alphanumeric.
                # This also handles potential None or non-string values gracefully.
                sanitized_ids = [
                    re.sub(r"[^a-zA-Z0-9]", "", str(id_val)) for id_val in id_batch
                ]
                valid_ids = [sfid for sfid in sanitized_ids if sfid]

                if not valid_ids:
                    log.warning(
                        f"Backup batch {i//batch_size + 1} skipped: no valid IDs after sanitization."
                    )
                    continue

                # Build safe-sized query for this batch
                quoted_ids = ",".join([f"'{id_val}'" for id_val in valid_ids])
                backup_soql = (
                    f"SELECT Id, Name, CreatedDate, LastModifiedDate "
                    f"FROM {object_name} WHERE Id IN ({quoted_ids})"
                )
                try:
                    # Query for this batch
                    batch_df = await self.sf_integration.query_data(backup_soql)
                    if batch_df is not None and not batch_df.empty:
                        all_backup_dfs.append(batch_df)
                        log.debug(
                            f"Backup batch {i//batch_size + 1}: {len(batch_df)} records"
                        )
                    else:
                        log.warning(
                            f"Backup batch {i//batch_size + 1} returned no data"
                        )

                except Exception as e:
                    log.error(f"Error in backup batch {i//batch_size + 1}: {e}")
                    # Continue with other batches even if one fails
                    continue

            # Combine all batch results
            if all_backup_dfs:
                backup_df = pd.concat(all_backup_dfs, ignore_index=True)

                # Remove any duplicate records (shouldn't happen, but safety first)
                backup_df = backup_df.drop_duplicates(subset=["Id"])

                log.info(f"Combined backup: {len(backup_df)} unique records")
            else:
                log.warning("No backup data retrieved from any batch")
                return None

            # Save to temporary file
            backup_file = tempfile.NamedTemporaryFile(
                mode="w", suffix=f"_{object_name}_backup.csv", delete=False
            )
            backup_df.to_csv(backup_file.name, index=False)
            backup_file.close()  # Important: close the file handle

            log.info(
                f"Created backup file: {backup_file.name} ({len(backup_df)} records)"
            )
            return backup_file.name

        except Exception as e:
            log.error(f"Error creating backup: {e}", exc_info=True)
            return None

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

        return None

    def _add_audit_entry(self, workflow_id: str, entry: Dict[str, Any]):
        """Add entry to audit log."""
        if workflow_id not in self.audit_logs:
            self.audit_logs[workflow_id] = []

        self.audit_logs[workflow_id].append(entry)

    def get_workflow_status(self, workflow_id: str) -> Optional[Dict[str, Any]]:
        """Get status of active workflow."""
        if workflow_id in self.active_workflows:
            config = self.active_workflows[workflow_id]
            return {
                "workflow_id": workflow_id,
                "type": type(config).__name__,
                "created_at": config.created_at.isoformat(),
                "dry_run": config.dry_run,
                "estimated_api_calls": config.estimated_api_calls,
            }
        return None

    def get_audit_log(self, workflow_id: str) -> List[Dict[str, Any]]:
        """Get audit log for workflow."""
        return self.audit_logs.get(workflow_id, [])


# Helper functions for integration with main application


def create_dedupe_workflow_config(object_name: str, **kwargs) -> DedupeWorkflowConfig:
    """Create deduplication workflow configuration."""
    return DedupeWorkflowConfig(object_name=object_name, **kwargs)


def create_lead_to_account_config(**kwargs) -> LeadToAccountConfig:
    """Create Lead-to-Account workflow configuration."""
    return LeadToAccountConfig(**kwargs)


async def execute_salesforce_workflow(
    sf_integration: SalesforceIntegration,
    workflow_type: str,
    config: WorkflowConfig,
    matches_df: pd.DataFrame,
    progress_callback=None,
) -> WorkflowResult:
    """Execute a Salesforce workflow."""
    engine = SalesforceWorkflowEngine(sf_integration)

    if workflow_type == "dedupe":
        return await engine.execute_dedupe_workflow(
            config, matches_df, progress_callback
        )
    elif workflow_type == "lead_to_account":
        return await engine.execute_lead_to_account_workflow(
            config, matches_df, progress_callback
        )
    else:
        raise ValueError(f"Unknown workflow type: {workflow_type}")


async def preview_salesforce_workflow(
    sf_integration: SalesforceIntegration,
    workflow_type: str,
    config: WorkflowConfig,
    matches_df: pd.DataFrame,
) -> PreviewResult:
    """Preview a Salesforce workflow."""
    engine = SalesforceWorkflowEngine(sf_integration)

    if workflow_type == "dedupe":
        return await engine.preview_dedupe_workflow(config, matches_df)
    elif workflow_type == "lead_to_account":
        return await engine.preview_lead_to_account_workflow(config, matches_df)
    else:
        raise ValueError(f"Unknown workflow type: {workflow_type}")
