"""Configuration and validation for embedding migration tool."""

from dataclasses import dataclass
from typing import Optional, Dict, List

# Predefined model migration mappings
MODEL_MAPPINGS: Dict[str, str] = {
    "BAAI/bge-m3": "h2oai/embeddinggemma-300m-qat-q8_0-unquantized",
    "BAAI/bge-large-en-v1.5": "mixedbread-ai/mxbai-embed-large-v1",
}


@dataclass
class MigrationConfig:
    """Configuration for the migration tool."""
    
    # Connection settings (required fields first)
    url: str
    admin_api_key: Optional[str] = None
    user_api_key: Optional[str] = None
    
    # Optional connection settings
    cert_path: Optional[str] = None
    api_key_expiry: str = "30 days"
    
    # Migration mode
    use_model_mappings: bool = False
    target_model: Optional[str] = None
    source_model: Optional[str] = None
    
    # Scope
    users: Optional[List[str]] = None
    collection_ids: Optional[List[str]] = None
    all_users: bool = False
    
    # Options
    dry_run: bool = False
    copy_document: bool = False
    skip_reparse: bool = False
    migrate_chats: bool = False
    ocr_model: str = "auto"
    
    # Manual move operations
    move_connectors: bool = False
    move_chats: bool = False
    move_from: Optional[str] = None
    move_to: Optional[str] = None

    # RAG verification
    verify_query: Optional[str] = None

    # Migration tracking
    db_path: str = "migration_tracking.db"
    force_remigrate: bool = False
    retry_failed: bool = False
    wait_for_completion: bool = False
    verify: bool = False
    max_concurrent_jobs: int = 1
    
    def validate(self):
        """Validate configuration for conflicting options."""
        errors = []

        # --max-concurrent-jobs validation
        if self.max_concurrent_jobs < 1:
            errors.append("--max-concurrent-jobs must be >= 1")
            raise ValueError("Configuration errors:\n" + "\n".join(f"  - {e}" for e in errors))
        
        # Must have one auth method
        is_admin_mode = bool(self.admin_api_key)
        is_self_service = bool(self.user_api_key)
        
        if is_admin_mode and is_self_service:
            errors.append("Cannot specify both --admin-key and --user-key")
        
        if not is_admin_mode and not is_self_service:
            errors.append("Must specify either --admin-key or --user-key")
        
        if errors:
            raise ValueError("Configuration errors:\n" + "\n".join(f"  - {e}" for e in errors))

        # Can't specify both --force-remigrate and --retry-failed (applies to all modes)
        if self.force_remigrate and self.retry_failed:
            raise ValueError("Configuration errors:\n  - Cannot specify both --force-remigrate and --retry-failed")

        # --skip-reparse requires copy_document=False
        if self.skip_reparse and self.copy_document:
            raise ValueError("Configuration errors:\n  - Cannot pass --copy-document with --skip-reparse (cannot copy documents when skipping re-parse)")

        # Move mode — manual connector/chat operations
        is_move_mode = self.move_connectors or self.move_chats
        if is_move_mode:
            if not self.move_from or not self.move_to:
                errors.append("--move-connectors/--move-chats requires both --from and --to")
            if self.move_from and self.move_to and self.move_from == self.move_to:
                errors.append("--from and --to must be different collections")
            incompatible = []
            if self.verify: incompatible.append("--verify")
            if self.verify_query: incompatible.append("--verify-query")
            if self.use_model_mappings: incompatible.append("--use-model-mappings")
            if self.target_model: incompatible.append("--target-model")
            if self.source_model: incompatible.append("--source-model")
            if self.users or self.all_users or self.collection_ids:
                incompatible.append("--users/--all-users/--collections")
            if self.dry_run: incompatible.append("--dry-run")
            if self.wait_for_completion: incompatible.append("--wait-for-completion")
            if self.force_remigrate: incompatible.append("--force-remigrate")
            if self.retry_failed: incompatible.append("--retry-failed")
            if self.migrate_chats: incompatible.append("--migrate-chats")
            if self.skip_reparse: incompatible.append("--skip-reparse")
            if incompatible:
                errors.append(f"Move mode cannot be combined with: {', '.join(incompatible)}")
            if errors:
                raise ValueError("Configuration errors:\n" + "\n".join(f"  - {e}" for e in errors))
            return

        # --verify-query requires --verify or --wait-for-completion
        if self.verify_query and not self.verify and not self.wait_for_completion:
            errors.append("--verify-query requires --verify or --wait-for-completion")
            raise ValueError("Configuration errors:\n" + "\n".join(f"  - {e}" for e in errors))

        # Check if this is verify-only mode
        is_verify_mode = self.verify
        has_migration_flags = (
            self.use_model_mappings or 
            self.target_model or 
            self.source_model
        )
        
        # Verify mode validations
        if is_verify_mode:
            # Cannot combine verify with migration flags
            if has_migration_flags:
                errors.append(
                    "Cannot combine --verify with migration flags "
                    "(--use-model-mappings, --target-model, --source-model)"
                )
            
            # Self-service cannot use admin-only scope flags
            if is_self_service and (self.users or self.all_users):
                errors.append("Self-service mode cannot use --users or --all-users")
            
            if errors:
                raise ValueError("Configuration errors:\n" + "\n".join(f"  - {e}" for e in errors))
            
            # Verify mode is valid - can optionally filter by users/collections
            return
        
        # Migration mode validations
        if is_self_service:
            # Self-service restrictions
            if self.users or self.all_users:
                errors.append("Self-service mode cannot use --users or --all-users")

            # Must have migration flags
            if not has_migration_flags:
                errors.append("Migration mode requires --use-model-mappings or --target-model")
                if self.migrate_chats:
                    errors.append("To migrate chats for completed migrations, use --verify --migrate-chats")
            
            # Can optionally specify --collections or migrate all (no scope required)
            if errors:
                raise ValueError("Configuration errors:\n" + "\n".join(f"  - {e}" for e in errors))
            return
        
        # Admin migration mode
        if not has_migration_flags:
            errors.append("Migration mode requires --use-model-mappings or --target-model")
            if self.migrate_chats:
                errors.append("To migrate chats for completed migrations, use --verify --migrate-chats")
        
        # Must specify scope for admin migration
        if not self.users and not self.all_users and not self.collection_ids:
            errors.append("Admin migration requires --users, --all-users, or --collections/--collections-file")

        # Can't specify both --users/--all-users AND --collections
        if self.collection_ids and (self.users or self.all_users):
            errors.append("Cannot specify --collections/--collections-file with --users or --all-users")
        
        # Can't specify both --users and --all-users
        if self.users and self.all_users:
            errors.append("Cannot specify both --users and --all-users")

        # Migration mode validation
        if self.use_model_mappings:
            # Model mappings mode - source/target will be ignored
            if self.target_model or self.source_model:
                errors.append("Cannot specify --source-model or --target-model with --use-model-mappings")
        else:
            # Manual mode - target-model is required
            if not self.target_model:
                errors.append("--target-model is required (or use --use-model-mappings)")
        
        if errors:
            raise ValueError("Configuration errors:\n" + "\n".join(f"  - {e}" for e in errors))
    
    def __str__(self):
        """String representation for logging."""
        if self.move_connectors or self.move_chats:
            ops = []
            if self.move_connectors: ops.append("connectors")
            if self.move_chats: ops.append("chats")
            return f"""
Move Operation:
  URL: {self.url}
  Moving: {', '.join(ops)}
  From: {self.move_from}
  To: {self.move_to}
"""

        if self.verify and not (self.use_model_mappings or self.target_model or self.source_model):
            # Verify-only mode
            if self.collection_ids:
                if len(self.collection_ids) == 1:
                    scope_str = f'Collection: {self.collection_ids[0]}'
                else:
                    scope_str = f'{len(self.collection_ids)} collection(s)'
            elif self.users:
                scope_str = ', '.join(self.users)
            else:
                scope_str = 'All'
            lines = [
                "",
                "Verify Configuration:",
                f"  URL: {self.url}",
                f"  Scope: {scope_str}",
                f"  Migrate Chats: {self.migrate_chats}",
            ]
            if self.verify_query:
                lines.append(f"  RAG Query: {self.verify_query}")
            lines.append("")
            return "\n".join(lines)

        if self.use_model_mappings:
            mode_str = f"Model Mappings ({len(MODEL_MAPPINGS)} models)"
        else:
            mode_str = f"{self.source_model or 'Any'} → {self.target_model}"
        
        # Format scope
        if self.all_users:
            scope_str = 'All users'
        elif self.collection_ids:
            if len(self.collection_ids) == 1:
                scope_str = f'Collection: {self.collection_ids[0]}'
            else:
                scope_str = f'Collections: {len(self.collection_ids)} collection(s)'
        elif self.users:
            if len(self.users) == 1:
                scope_str = f'User: {self.users[0]}'
            else:
                scope_str = f'Users: {", ".join(self.users)}'
        else:
            scope_str = 'None'
        
        lines = [
            "",
            "Migration Configuration:",
            f"  URL: {self.url}",
            f"  Mode: {mode_str}",
            f"  Scope: {scope_str}",
            f"  Copy Documents: {self.copy_document}",
            f"  Skip Reparse: {self.skip_reparse}",
        ]
        if self.wait_for_completion:
            lines.append(f"  Wait for Completion: True")
            if self.max_concurrent_jobs > 1:
                lines.append(f"  Max Concurrent Jobs: {self.max_concurrent_jobs}")
        if self.migrate_chats:
            lines.append(f"  Migrate Chats: True")
        if self.force_remigrate:
            lines.append(f"  Force Remigrate: True")
        if self.retry_failed:
            lines.append(f"  Retry Failed: True")
        if self.verify_query:
            lines.append(f"  RAG Query: {self.verify_query}")
        if self.dry_run:
            lines.append(f"  Dry Run: True")
        lines.append("")
        return "\n".join(lines)

    def __repr__(self):
        return self.__str__()
