#!/usr/bin/env python3
"""
PrecipGen Convenience API Workflow Patterns

This module demonstrates common workflow patterns and best practices for using
the PrecipGen Convenience API in various scenarios and integration contexts.

Author: PrecipGen Development Team
Version: 0.1.3
"""

import os
import json
from pathlib import Path
from typing import Dict, List, Optional, Any, Tuple
from datetime import datetime

from precipgen.convenience import ConvenienceAPI, BatchProcessor
from precipgen.convenience.config import (
    AnalysisConfig, TemplateConfig, OutputConfig, BatchConfig
)
from precipgen.convenience.templates.template_examples import get_template_config

def pattern_1_fully_automated_workflow():
    """
    Pattern 1: Fully Automated Workflow
    
    Single function call that handles everything from location to parameters.
    Best for: Quick analyses, prototyping, simple applications.
    """
    print("=" * 60)
    print("Pattern 1: Fully Automated Workflow")
    print("=" * 60)
    
    api = ConvenienceAPI()
    
    # Simplest possible usage - just provide a location
    locations_to_test = [
        "Denver, CO",
        (39.7392, -104.9903),  # Denver coordinates
        "Salt Lake City, UT"
    ]
    
    print("Demonstrating fully automated analysis...")
    
    for location in locations_to_test:
        try:
            print(f"\nAnalyzing: {location}")
            
            # Single function call does everything
            result = api.analyze_precipitation(location)
            
            print(f"✅ Success!")
            print(f"   Station: {result.station_info.name}")
            print(f"   Data years: {result.station_info.data_years}")
            print(f"   Quality: {result.station_info.data_quality_score:.1%}")
            print(f"   Report: {Path(result.html_report).name}")
            
        except Exception as e:
            print(f"❌ Failed: {e}")
    
    print("\nPattern 1 Use Cases:")
    print("- Quick climate assessments")
    print("- Prototyping and exploration")
    print("- Educational demonstrations")
    print("- Simple automation scripts")

def pattern_2_semi_interactive_workflow():
    """
    Pattern 2: Semi-Interactive Workflow
    
    Automated discovery with user review and selection of stations.
    Best for: Quality control, site-specific studies, expert users.
    """
    print("\n" + "=" * 60)
    print("Pattern 2: Semi-Interactive Workflow")
    print("=" * 60)
    
    api = ConvenienceAPI()
    
    def interactive_station_selection(location: str, max_candidates: int = 5) -> Optional[str]:
        """Simulate interactive station selection process."""
        
        try:
            # Step 1: Discover candidate stations
            print(f"Discovering stations near {location}...")
            candidates = api.discover_stations(location)
            
            if not candidates:
                print("No suitable stations found.")
                return None
            
            # Step 2: Present options (simulated user review)
            print(f"Found {len(candidates)} candidates. Top {max_candidates}:")
            
            for i, candidate in enumerate(candidates[:max_candidates]):
                print(f"  {i+1}. {candidate.name} ({candidate.id})")
                print(f"     Distance: {candidate.distance_km:.1f} km")
                print(f"     Period: {candidate.first_year}-{candidate.last_year}")
                print(f"     Quality: {candidate.quality_score:.1%}")
                print(f"     Completeness: {candidate.data_completeness:.1%}")
                
                # Show suitability notes
                if candidate.suitability_notes:
                    print(f"     Notes: {', '.join(candidate.suitability_notes[:2])}")
                print()
            
            # Step 3: Simulate selection (choose best quality)
            best_candidate = max(candidates[:max_candidates], 
                               key=lambda x: x.quality_score)
            
            print(f"Selected: {best_candidate.name} (highest quality)")
            
            # Step 4: Preview selected station
            preview = api.preview_station_data(best_candidate.id)
            print(f"Preview recommendation: {preview.recommendation}")
            
            return best_candidate.id
            
        except Exception as e:
            print(f"Station selection failed: {e}")
            return None
    
    # Demonstrate semi-interactive workflow
    test_location = "Phoenix, AZ"
    
    station_id = interactive_station_selection(test_location)
    
    if station_id:
        try:
            print(f"Running full analysis with selected station...")
            
            result = api.analyze_precipitation(
                location=test_location,
                station_id=station_id
            )
            
            print(f"✅ Analysis completed!")
            print(f"   Final station: {result.station_info.name}")
            print(f"   Report: {Path(result.html_report).name}")
            
        except Exception as e:
            print(f"❌ Analysis failed: {e}")
    
    print("\nPattern 2 Use Cases:")
    print("- Quality-critical applications")
    print("- Site-specific engineering studies")
    print("- Research requiring data validation")
    print("- Expert user workflows")

def pattern_3_expert_workflow():
    """
    Pattern 3: Expert Workflow
    
    Full control over all analysis parameters and configurations.
    Best for: Research, specialized applications, advanced users.
    """
    print("\n" + "=" * 60)
    print("Pattern 3: Expert Workflow")
    print("=" * 60)
    
    # Expert-level configuration
    expert_analysis_config = AnalysisConfig(
        min_years_data=25,              # Strict data requirements
        search_radius_km=30,            # Tight geographic constraint
        wet_day_threshold=0.2,          # Custom threshold
        trend_window_years=35,          # Long-term trend analysis
        validation_realizations=300,    # Extensive validation
        parallel_execution=True,
        max_workers=4
    )
    
    expert_output_config = OutputConfig(
        base_output_dir="./expert_analysis",
        organize_by_location=True,
        create_timestamped_dirs=True,
        use_location_in_filename=True,
        use_timestamp_in_filename=True,
        filename_sanitization=True
    )
    
    expert_template_config = get_template_config("scientific")
    expert_template_config.custom_variables.update({
        "analysis_level": "expert",
        "quality_control": "peer_reviewed",
        "methodology": "Enhanced WGEN with Extended Validation",
        "researcher": "Expert Climate Analyst",
        "institution": "Advanced Climate Research Institute"
    })
    
    # Add custom CSS for expert reports
    expert_template_config.custom_css = """
        .expert-analysis {
            border: 2px solid #2c3e50;
            background: #f8f9fa;
            padding: 15px;
            margin: 20px 0;
        }
        .quality-metrics {
            background: #e8f4fd;
            border-left: 4px solid #3498db;
            padding: 15px;
        }
        .expert-recommendations {
            background: #fff3cd;
            border: 1px solid #ffeaa7;
            padding: 15px;
            border-radius: 5px;
        }
    """
    
    api = ConvenienceAPI()
    
    print("Expert Workflow Configuration:")
    print(f"  - Minimum data years: {expert_analysis_config.min_years_data}")
    print(f"  - Search radius: {expert_analysis_config.search_radius_km} km")
    print(f"  - Wet day threshold: {expert_analysis_config.wet_day_threshold} mm")
    print(f"  - Trend window: {expert_analysis_config.trend_window_years} years")
    print(f"  - Validation runs: {expert_analysis_config.validation_realizations}")
    print(f"  - Template: {expert_template_config.template_name}")
    print()
    
    try:
        # Expert analysis with full configuration control
        result = api.analyze_precipitation(
            location="Boulder, CO",
            analysis_config=expert_analysis_config,
            output_config=expert_output_config,
            template_config=expert_template_config
        )
        
        print(f"✅ Expert analysis completed!")
        print(f"   Station: {result.station_info.name}")
        print(f"   Analysis quality: Expert-level validation")
        print(f"   Output directory: {expert_output_config.base_output_dir}")
        print(f"   Report: {Path(result.html_report).name}")
        
        # Expert-level result analysis
        print(f"\n🔬 Expert Analysis Results:")
        print(f"   Data completeness: {result.station_info.data_completeness:.2%}")
        print(f"   Quality score: {result.station_info.data_quality_score:.2%}")
        print(f"   Validation score: {result.validation_report.validation_score:.2%}")
        
        if result.has_trends:
            trend_count = len(result.trend_analysis.significant_parameters)
            print(f"   Significant trends: {trend_count} parameters")
        
        if result.metadata.warnings:
            print(f"   Warnings: {len(result.metadata.warnings)} items")
        
    except Exception as e:
        print(f"❌ Expert analysis failed: {e}")
    
    print("\nPattern 3 Use Cases:")
    print("- Peer-reviewed research")
    print("- High-stakes engineering projects")
    print("- Method development and validation")
    print("- Regulatory compliance studies")

def pattern_4_batch_processing_workflow():
    """
    Pattern 4: Batch Processing Workflow
    
    Efficient processing of multiple locations with comprehensive error handling.
    Best for: Regional studies, multi-site projects, operational systems.
    """
    print("\n" + "=" * 60)
    print("Pattern 4: Batch Processing Workflow")
    print("=" * 60)
    
    # Define batch processing scenario
    batch_locations = [
        "Reno, NV",
        "Carson City, NV", 
        "Lake Tahoe, CA",
        "Truckee, CA",
        "Mammoth Lakes, CA"
    ]
    
    # Batch configuration
    batch_config = BatchConfig(
        parallel_execution=True,
        max_workers=3,
        continue_on_error=True,
        save_intermediate_results=True,
        generate_summary_report=True,
        parallelism_strategy="by_location"
    )
    
    # Analysis configuration for batch
    batch_analysis_config = AnalysisConfig(
        min_years_data=20,
        search_radius_km=60,
        validation_realizations=150,
        parallel_execution=True
    )
    
    # Template for batch reports
    batch_template_config = get_template_config("engineering")
    batch_template_config.custom_variables.update({
        "project_name": "Sierra Nevada Regional Assessment",
        "batch_id": f"BATCH_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
        "processing_mode": "automated_batch"
    })
    
    processor = BatchProcessor()
    
    print("Batch Processing Configuration:")
    print(f"  - Locations: {len(batch_locations)}")
    print(f"  - Parallel workers: {batch_config.max_workers}")
    print(f"  - Error handling: Continue on failure")
    print(f"  - Intermediate saves: Enabled")
    print(f"  - Summary report: Enabled")
    print()
    
    try:
        # Execute batch processing
        batch_results = processor.analyze_multiple_locations(
            locations=batch_locations,
            analysis_config=batch_analysis_config,
            batch_config=batch_config,
            template_config=batch_template_config
        )
        
        print(f"✅ Batch processing completed!")
        print(f"   Total locations: {len(batch_locations)}")
        print(f"   Successful: {batch_results.batch_summary.successful_analyses}")
        print(f"   Failed: {batch_results.batch_summary.failed_analyses}")
        print(f"   Success rate: {batch_results.success_rate:.1%}")
        print(f"   Processing time: {batch_results.batch_summary.processing_time:.1f} seconds")
        
        if batch_results.summary_report_path:
            print(f"   Summary report: {Path(batch_results.summary_report_path).name}")
        
        if batch_results.index_report_path:
            print(f"   Index report: {Path(batch_results.index_report_path).name}")
        
        # Show batch insights
        if batch_results.batch_summary.recommendations:
            print(f"\n📊 Batch Insights:")
            for insight in batch_results.batch_summary.recommendations[:3]:
                print(f"   - {insight}")
        
    except Exception as e:
        print(f"❌ Batch processing failed: {e}")
    
    print("\nPattern 4 Use Cases:")
    print("- Regional climate assessments")
    print("- Multi-site infrastructure projects")
    print("- Operational monitoring systems")
    print("- Large-scale research studies")

def pattern_5_integration_workflow():
    """
    Pattern 5: Integration Workflow
    
    Integration with existing systems, databases, and automated pipelines.
    Best for: Production systems, automated workflows, data pipelines.
    """
    print("\n" + "=" * 60)
    print("Pattern 5: Integration Workflow")
    print("=" * 60)
    
    def simulate_database_integration():
        """Simulate integration with external database or system."""
        
        # Simulate reading locations from database
        database_locations = [
            {"id": 1, "name": "Site Alpha", "location": "Boise, ID", "priority": "high"},
            {"id": 2, "name": "Site Beta", "location": "Pocatello, ID", "priority": "medium"},
            {"id": 3, "name": "Site Gamma", "location": "Twin Falls, ID", "priority": "low"}
        ]
        
        print("Simulating database integration...")
        print(f"Retrieved {len(database_locations)} sites from database")
        
        api = ConvenienceAPI()
        results_for_database = []
        
        for site in database_locations:
            print(f"\nProcessing {site['name']} ({site['location']})...")
            
            try:
                # Configure analysis based on site priority
                if site['priority'] == 'high':
                    config = AnalysisConfig(
                        min_years_data=25,
                        validation_realizations=200
                    )
                elif site['priority'] == 'medium':
                    config = AnalysisConfig(
                        min_years_data=20,
                        validation_realizations=150
                    )
                else:  # low priority
                    config = AnalysisConfig(
                        min_years_data=15,
                        validation_realizations=100
                    )
                
                # Run analysis
                result = api.analyze_precipitation(
                    location=site['location'],
                    analysis_config=config
                )
                
                # Prepare data for database storage
                database_record = {
                    "site_id": site['id'],
                    "site_name": site['name'],
                    "station_id": result.station_info.id,
                    "station_name": result.station_info.name,
                    "data_years": result.station_info.data_years,
                    "quality_score": result.station_info.data_quality_score,
                    "validation_score": result.validation_report.validation_score,
                    "has_trends": result.has_trends,
                    "report_path": result.html_report,
                    "analysis_date": datetime.now().isoformat(),
                    "priority": site['priority']
                }
                
                results_for_database.append(database_record)
                
                print(f"   ✅ Success: {result.station_info.name}")
                print(f"   Database record prepared for site {site['id']}")
                
            except Exception as e:
                print(f"   ❌ Failed: {e}")
                
                # Create failure record for database
                failure_record = {
                    "site_id": site['id'],
                    "site_name": site['name'],
                    "error": str(e),
                    "analysis_date": datetime.now().isoformat(),
                    "status": "failed"
                }
                results_for_database.append(failure_record)
        
        # Simulate database storage
        print(f"\nStoring {len(results_for_database)} records to database...")
        
        # In real integration, this would be actual database operations
        for record in results_for_database:
            if "error" not in record:
                print(f"   INSERT: Site {record['site_id']} - {record['station_name']}")
            else:
                print(f"   ERROR: Site {record['site_id']} - {record['error']}")
        
        return results_for_database
    
    def simulate_api_integration():
        """Simulate REST API integration."""
        
        print("\nSimulating REST API integration...")
        
        # Simulate API request payload
        api_request = {
            "locations": ["Missoula, MT", "Billings, MT"],
            "analysis_type": "standard",
            "output_format": "json",
            "include_plots": False
        }
        
        print(f"API Request: {json.dumps(api_request, indent=2)}")
        
        api = ConvenienceAPI()
        api_response = {
            "status": "success",
            "results": [],
            "metadata": {
                "processing_time": 0,
                "timestamp": datetime.now().isoformat(),
                "version": "0.1.3"
            }
        }
        
        start_time = datetime.now()
        
        for location in api_request["locations"]:
            try:
                result = api.analyze_precipitation(location)
                
                # Convert result to API response format
                result_data = {
                    "location": location,
                    "station": {
                        "id": result.station_info.id,
                        "name": result.station_info.name,
                        "coordinates": [result.station_info.latitude, result.station_info.longitude],
                        "data_years": result.station_info.data_years,
                        "quality_score": result.station_info.data_quality_score
                    },
                    "validation": {
                        "score": result.validation_report.validation_score,
                        "performance": result.validation_report.overall_performance
                    },
                    "trends": {
                        "detected": result.has_trends,
                        "count": len(result.trend_analysis.significant_parameters) if result.has_trends else 0
                    }
                }
                
                api_response["results"].append(result_data)
                
            except Exception as e:
                error_data = {
                    "location": location,
                    "error": str(e),
                    "status": "failed"
                }
                api_response["results"].append(error_data)
        
        # Calculate processing time
        processing_time = (datetime.now() - start_time).total_seconds()
        api_response["metadata"]["processing_time"] = processing_time
        
        print(f"API Response: {json.dumps(api_response, indent=2)}")
        
        return api_response
    
    # Run integration simulations
    database_results = simulate_database_integration()
    api_results = simulate_api_integration()
    
    print("\nPattern 5 Use Cases:")
    print("- Production web services")
    print("- Automated data pipelines")
    print("- Enterprise system integration")
    print("- Operational monitoring systems")
    print("- Cloud-based processing services")

def pattern_6_error_handling_workflow():
    """
    Pattern 6: Robust Error Handling Workflow
    
    Comprehensive error handling, fallback strategies, and recovery mechanisms.
    Best for: Production systems, automated operations, critical applications.
    """
    print("\n" + "=" * 60)
    print("Pattern 6: Robust Error Handling Workflow")
    print("=" * 60)
    
    def robust_precipitation_analysis(location: str, max_retries: int = 3) -> Dict[str, Any]:
        """
        Robust analysis with comprehensive error handling and fallback strategies.
        """
        
        api = ConvenienceAPI()
        
        # Progressive fallback configurations
        fallback_configs = [
            # Primary: High standards
            {
                "name": "Primary",
                "config": AnalysisConfig(
                    min_years_data=25,
                    search_radius_km=50,
                    validation_realizations=200
                )
            },
            # Fallback 1: Moderate standards
            {
                "name": "Fallback 1",
                "config": AnalysisConfig(
                    min_years_data=20,
                    search_radius_km=75,
                    validation_realizations=150
                )
            },
            # Fallback 2: Relaxed standards
            {
                "name": "Fallback 2", 
                "config": AnalysisConfig(
                    min_years_data=15,
                    search_radius_km=100,
                    validation_realizations=100
                )
            },
            # Emergency: Minimal standards
            {
                "name": "Emergency",
                "config": AnalysisConfig(
                    min_years_data=10,
                    search_radius_km=150,
                    validation_realizations=50
                )
            }
        ]
        
        analysis_log = {
            "location": location,
            "attempts": [],
            "final_result": None,
            "success": False,
            "fallback_used": None,
            "warnings": [],
            "errors": []
        }
        
        print(f"Starting robust analysis for: {location}")
        
        for attempt_num, fallback in enumerate(fallback_configs):
            if attempt_num >= max_retries:
                break
                
            print(f"  Attempt {attempt_num + 1}: {fallback['name']} configuration")
            
            attempt_log = {
                "attempt": attempt_num + 1,
                "configuration": fallback['name'],
                "timestamp": datetime.now().isoformat(),
                "success": False,
                "error": None
            }
            
            try:
                result = api.analyze_precipitation(
                    location=location,
                    analysis_config=fallback['config']
                )
                
                # Quality validation
                min_quality = 0.6 - (attempt_num * 0.1)  # Progressive relaxation
                
                if result.station_info.data_quality_score >= min_quality:
                    print(f"    ✅ Success with {fallback['name']} configuration")
                    print(f"    Station: {result.station_info.name}")
                    print(f"    Quality: {result.station_info.data_quality_score:.1%}")
                    
                    attempt_log["success"] = True
                    analysis_log["final_result"] = result
                    analysis_log["success"] = True
                    analysis_log["fallback_used"] = fallback['name']
                    
                    if attempt_num > 0:
                        analysis_log["warnings"].append(f"Required fallback configuration: {fallback['name']}")
                    
                    analysis_log["attempts"].append(attempt_log)
                    return analysis_log
                    
                else:
                    warning = f"Quality too low: {result.station_info.data_quality_score:.1%} < {min_quality:.1%}"
                    print(f"    ⚠️  {warning}")
                    analysis_log["warnings"].append(warning)
                    attempt_log["error"] = warning
                    
            except Exception as e:
                error_msg = f"{fallback['name']} failed: {str(e)}"
                print(f"    ❌ {error_msg}")
                analysis_log["errors"].append(error_msg)
                attempt_log["error"] = error_msg
            
            analysis_log["attempts"].append(attempt_log)
        
        # All attempts failed
        print(f"  🚫 All {len(fallback_configs)} configurations failed")
        analysis_log["success"] = False
        
        return analysis_log
    
    # Test robust error handling
    test_locations = [
        "Anchorage, AK",    # Challenging location
        "Miami, FL",        # Good location
        "Nowhere, XX"       # Invalid location
    ]
    
    results = []
    
    for location in test_locations:
        print(f"\nTesting robust analysis: {location}")
        result = robust_precipitation_analysis(location)
        results.append(result)
        
        if result["success"]:
            print(f"✅ Final result: Success with {result['fallback_used']} configuration")
            if result["warnings"]:
                print(f"   Warnings: {len(result['warnings'])}")
        else:
            print(f"❌ Final result: All attempts failed")
            print(f"   Errors: {len(result['errors'])}")
    
    # Summary of error handling results
    print(f"\n📊 Error Handling Summary:")
    successful = sum(1 for r in results if r["success"])
    print(f"   Successful analyses: {successful}/{len(results)}")
    
    fallback_usage = {}
    for result in results:
        if result["success"] and result["fallback_used"]:
            fallback = result["fallback_used"]
            fallback_usage[fallback] = fallback_usage.get(fallback, 0) + 1
    
    if fallback_usage:
        print(f"   Fallback configuration usage:")
        for config, count in fallback_usage.items():
            print(f"     {config}: {count} times")
    
    print("\nPattern 6 Use Cases:")
    print("- Production systems requiring high reliability")
    print("- Automated processing pipelines")
    print("- Critical infrastructure applications")
    print("- Systems with strict uptime requirements")

def main():
    """
    Demonstrate all workflow patterns.
    
    This function shows the complete range of workflow patterns available
    with the PrecipGen Convenience API for different use cases and requirements.
    """
    print("PrecipGen Convenience API Workflow Patterns")
    print("Version 0.1.3")
    print("=" * 60)
    print()
    print("This module demonstrates common workflow patterns for different")
    print("use cases and integration scenarios with the Convenience API.")
    print()
    
    # Create output directory
    output_dir = Path("./workflow_patterns_output")
    output_dir.mkdir(exist_ok=True)
    print(f"Workflow outputs will be saved to: {output_dir.absolute()}")
    print()
    
    # Run workflow patterns
    patterns = [
        ("Fully Automated", pattern_1_fully_automated_workflow),
        ("Semi-Interactive", pattern_2_semi_interactive_workflow),
        ("Expert Configuration", pattern_3_expert_workflow),
        ("Batch Processing", pattern_4_batch_processing_workflow),
        ("System Integration", pattern_5_integration_workflow),
        ("Error Handling", pattern_6_error_handling_workflow)
    ]
    
    for pattern_name, pattern_func in patterns:
        try:
            pattern_func()
        except KeyboardInterrupt:
            print(f"\n{pattern_name} pattern interrupted by user.")
            break
        except Exception as e:
            print(f"❌ {pattern_name} pattern failed: {e}")
    
    print("\n" + "=" * 60)
    print("Workflow Patterns Summary")
    print("=" * 60)
    print()
    print("Pattern Selection Guide:")
    print()
    print("1. Fully Automated - Quick analyses, prototyping")
    print("2. Semi-Interactive - Quality control, expert review")
    print("3. Expert Configuration - Research, specialized applications")
    print("4. Batch Processing - Regional studies, multi-site projects")
    print("5. System Integration - Production systems, APIs")
    print("6. Error Handling - Critical applications, automation")
    print()
    print("Choose the pattern that best matches your:")
    print("- Use case requirements")
    print("- Quality control needs")
    print("- Integration constraints")
    print("- Error tolerance")
    print("- Performance requirements")

if __name__ == "__main__":
    main()