"""
CLI commands for advanced asset management - Issue #144.

This module provides command-line interface for advanced asset operations
including batch processing, discovery, and analytics.
"""

from pathlib import Path
from typing import List, Optional, Dict, Any
from dataclasses import dataclass

from markitect.assets import AssetManager
from markitect.assets.batch_processor import BatchAssetProcessor, ConflictResolution
from markitect.assets.discovery import AssetDiscoveryEngine
from markitect.assets.optimizer import AssetOptimizer, OptimizationProfile
from markitect.assets.analytics import AssetAnalytics


@dataclass
class CLIResult:
    """Result of CLI command execution."""
    success: bool
    message: str
    data: Optional[Dict[str, Any]] = None


@dataclass
class BatchImportCLIResult(CLIResult):
    """Result of batch import CLI command."""
    imported_count: int = 0
    skipped_count: int = 0
    error_count: int = 0


@dataclass
class StatisticsCLIResult(CLIResult):
    """Result of statistics CLI command."""
    total_assets: int = 0
    total_size: int = 0
    optimization_potential: Optional[Dict[str, Any]] = None


@dataclass
class DiscoveryCLIResult(CLIResult):
    """Result of discovery CLI command."""
    total_references: int = 0
    broken_links: int = 0
    discovered_assets: int = 0


@dataclass
class AssetAddResult(CLIResult):
    """Result of asset addition."""
    asset_hash: Optional[str] = None


@dataclass
class AssetListResult(CLIResult):
    """Result of asset listing."""
    assets: Optional[List[Dict[str, Any]]] = None


@dataclass
class AssetInfoResult(CLIResult):
    """Result of asset info retrieval."""
    asset_info: Optional[Dict[str, Any]] = None


class AssetCommands:
    """CLI commands for asset management."""

    def __init__(self, asset_manager: AssetManager):
        """Initialize asset commands."""
        self.asset_manager = asset_manager
        self.batch_processor = BatchAssetProcessor(asset_manager)
        self.discovery_engine = AssetDiscoveryEngine(asset_manager)
        self.optimizer = AssetOptimizer()
        self.analytics = AssetAnalytics(asset_manager)

    def batch_import(self, source_directory: str, recursive: bool = True,
                    patterns: Optional[List[str]] = None, auto_optimize: bool = False,
                    progress: bool = True) -> BatchImportCLIResult:
        """Execute batch import command."""
        try:
            source_path = Path(source_directory)

            if not source_path.exists():
                return BatchImportCLIResult(
                    success=False,
                    message=f"Source directory does not exist: {source_directory}"
                )

            # Set up progress reporting if requested
            progress_reporter = None
            if progress:
                progress_reporter = self._create_progress_reporter()

            # Configure batch processor
            self.batch_processor.progress_reporter = progress_reporter

            # Execute batch import
            result = self.batch_processor.import_directory(
                source_path=source_path,
                recursive=recursive,
                patterns=patterns,
                conflict_resolution=ConflictResolution.SKIP,
                auto_optimize=auto_optimize
            )

            return BatchImportCLIResult(
                success=True,
                message=f"Batch import completed: {result.successful_imports} assets imported",
                imported_count=result.successful_imports,
                skipped_count=result.skipped_files,
                error_count=result.failed_imports,
                data={
                    "processing_time": result.processing_time_seconds,
                    "total_size": result.total_size_bytes
                }
            )

        except Exception as e:
            return BatchImportCLIResult(
                success=False,
                message=f"Batch import failed: {str(e)}"
            )

    def get_statistics(self, include_usage: bool = False,
                      include_optimization_potential: bool = False) -> StatisticsCLIResult:
        """Get asset library statistics."""
        try:
            # Get basic statistics
            all_assets = self.asset_manager.registry.list_assets_as_objects()
            total_assets = len(all_assets)
            total_size = sum(asset.size_bytes for asset in all_assets)

            # Get usage statistics if requested
            usage_data = None
            if include_usage:
                usage_report = self.analytics.generate_usage_report()
                usage_data = {
                    "utilization_rate": usage_report.utilization_rate,
                    "used_assets": usage_report.used_assets,
                    "unused_assets": usage_report.unused_assets
                }

            # Get optimization potential if requested
            optimization_data = None
            if include_optimization_potential:
                project_insights = self.analytics.analyze_project_assets(Path.cwd())
                optimization_data = {
                    "potential_savings_bytes": project_insights.optimization_potential_bytes,
                    "duplicate_assets": project_insights.duplicate_assets,
                    "recommendations": project_insights.recommendations
                }

            message = f"Total assets: {total_assets}, Total size: {total_size:,} bytes"

            return StatisticsCLIResult(
                success=True,
                message=message,
                total_assets=total_assets,
                total_size=total_size,
                optimization_potential=optimization_data,
                data={
                    "usage_statistics": usage_data,
                    "optimization_potential": optimization_data
                }
            )

        except Exception as e:
            return StatisticsCLIResult(
                success=False,
                message=f"Failed to get statistics: {str(e)}"
            )

    def discover_assets(self, scan_directory: str, auto_register: bool = False,
                       report_broken_links: bool = True) -> DiscoveryCLIResult:
        """Discover assets in project files."""
        try:
            scan_path = Path(scan_directory)

            if not scan_path.exists():
                return DiscoveryCLIResult(
                    success=False,
                    message=f"Scan directory does not exist: {scan_directory}"
                )

            # Scan for asset references
            scan_result = self.discovery_engine.scan_directory(
                scan_path,
                recursive=True
            )

            discovered_count = 0

            # Auto-register if requested
            if auto_register:
                registration_result = self.discovery_engine.auto_register_assets(
                    scan_path,
                    register_existing=True,
                    skip_broken=True
                )
                discovered_count = registration_result.registered_count

            message_parts = [
                f"Found {len(scan_result.asset_references)} asset references",
                f"Broken links: {len(scan_result.broken_links)}"
            ]

            if auto_register:
                message_parts.append(f"Registered: {discovered_count} assets")

            return DiscoveryCLIResult(
                success=True,
                message=", ".join(message_parts),
                total_references=len(scan_result.asset_references),
                broken_links=len(scan_result.broken_links),
                discovered_assets=discovered_count,
                data={
                    "scanned_files": len(scan_result.scanned_files),
                    "processing_time": scan_result.processing_time,
                    "broken_links": [
                        {
                            "file": str(ref.source_file),
                            "asset_path": ref.asset_path,
                            "line": ref.line_number
                        }
                        for ref in scan_result.broken_links
                    ] if report_broken_links else []
                }
            )

        except Exception as e:
            return DiscoveryCLIResult(
                success=False,
                message=f"Asset discovery failed: {str(e)}"
            )

    def optimize_assets(self, asset_patterns: Optional[List[str]] = None,
                       profile: str = "balanced", dry_run: bool = False) -> CLIResult:
        """Optimize assets in the library."""
        try:
            # Configure optimization profile
            if profile == "conservative":
                opt_profile = OptimizationProfile.CONSERVATIVE
            elif profile == "aggressive":
                opt_profile = OptimizationProfile.AGGRESSIVE
            else:
                opt_profile = OptimizationProfile.BALANCED

            self.optimizer.profile = opt_profile

            # Get assets to optimize
            all_assets = self.asset_manager.registry.list_assets_as_objects()

            # Filter by patterns if provided
            assets_to_optimize = []
            for asset in all_assets:
                if asset_patterns:
                    # Check if asset matches any pattern
                    if any(pattern in asset.filename for pattern in asset_patterns):
                        assets_to_optimize.append(Path(asset.filename))
                else:
                    # Optimize images and documents
                    if Path(asset.filename).suffix.lower() in ['.png', '.jpg', '.jpeg', '.svg', '.pdf']:
                        assets_to_optimize.append(Path(asset.filename))

            if dry_run:
                return CLIResult(
                    success=True,
                    message=f"Dry run: Would optimize {len(assets_to_optimize)} assets",
                    data={"assets_to_optimize": [str(p) for p in assets_to_optimize]}
                )

            # Execute optimization
            optimization_results = self.optimizer.optimize_batch(
                assets_to_optimize,
                max_concurrent=2
            )

            successful_optimizations = [r for r in optimization_results if r.success]
            total_savings = sum(r.original_size - r.optimized_size for r in successful_optimizations)

            return CLIResult(
                success=True,
                message=f"Optimized {len(successful_optimizations)} assets, saved {total_savings:,} bytes",
                data={
                    "optimized_count": len(successful_optimizations),
                    "failed_count": len(optimization_results) - len(successful_optimizations),
                    "total_savings_bytes": total_savings,
                    "optimization_profile": profile
                }
            )

        except Exception as e:
            return CLIResult(
                success=False,
                message=f"Asset optimization failed: {str(e)}"
            )

    def cleanup_unused(self, dry_run: bool = True, min_size_bytes: int = 0) -> CLIResult:
        """Clean up unused assets."""
        try:
            # Generate usage report
            usage_report = self.analytics.generate_usage_report(include_unused=True)
            unused_assets = usage_report.unused_assets_list

            # Filter by minimum size
            if min_size_bytes > 0:
                unused_assets = [asset for asset in unused_assets if asset["size_bytes"] >= min_size_bytes]

            total_size_to_free = sum(asset["size_bytes"] for asset in unused_assets)

            if dry_run:
                return CLIResult(
                    success=True,
                    message=f"Dry run: Would remove {len(unused_assets)} unused assets, freeing {total_size_to_free:,} bytes",
                    data={
                        "unused_assets": unused_assets,
                        "total_size_to_free": total_size_to_free
                    }
                )

            # Actually remove unused assets (simplified implementation)
            removed_count = 0
            for asset in unused_assets:
                try:
                    # Would remove the actual asset file here
                    removed_count += 1
                except Exception:
                    pass

            return CLIResult(
                success=True,
                message=f"Removed {removed_count} unused assets, freed {total_size_to_free:,} bytes",
                data={
                    "removed_count": removed_count,
                    "freed_bytes": total_size_to_free
                }
            )

        except Exception as e:
            return CLIResult(
                success=False,
                message=f"Cleanup failed: {str(e)}"
            )

    def _create_progress_reporter(self):
        """Create a simple progress reporter for CLI."""
        class CLIProgressReporter:
            def __init__(self):
                self.total = 0
                self.current = 0

            def start(self, total_items):
                self.total = total_items
                self.current = 0
                print(f"Processing {total_items} items...")

            def update(self, current, item_name=""):
                self.current = current
                if self.total > 0:
                    progress = (current / self.total) * 100
                    print(f"Progress: {progress:.1f}% ({current}/{self.total}) - {item_name}")

            def finish(self):
                print("Processing complete!")

        return CLIProgressReporter()

    def add_asset(self, file_path: str) -> AssetAddResult:
        """Add a single asset via CLI."""
        try:
            asset_path = Path(file_path)
            if not asset_path.exists():
                return AssetAddResult(
                    success=False,
                    message=f"File does not exist: {file_path}"
                )

            # Add asset using asset manager
            result = self.asset_manager.add_asset(asset_path)

            if result and 'content_hash' in result:
                return AssetAddResult(
                    success=True,
                    message=f"Asset added successfully: {asset_path.name}",
                    asset_hash=result['content_hash']
                )
            else:
                return AssetAddResult(
                    success=False,
                    message=f"Failed to add asset: {file_path}"
                )

        except Exception as e:
            return AssetAddResult(
                success=False,
                message=f"Failed to add asset: {str(e)}"
            )

    def list_assets(self) -> AssetListResult:
        """List all assets via CLI."""
        try:
            assets = self.asset_manager.registry.list_assets()
            return AssetListResult(
                success=True,
                message=f"Found {len(assets)} assets",
                assets=assets
            )
        except Exception as e:
            return AssetListResult(
                success=False,
                message=f"Failed to list assets: {str(e)}",
                assets=[]
            )

    def get_asset_info(self, content_hash: str) -> AssetInfoResult:
        """Get information about a specific asset."""
        try:
            asset_info = self.asset_manager.registry.get_asset(content_hash)
            return AssetInfoResult(
                success=True,
                message=f"Asset info retrieved for {content_hash[:8]}...",
                asset_info=asset_info
            )
        except Exception as e:
            return AssetInfoResult(
                success=False,
                message=f"Failed to get asset info: {str(e)}"
            )