"""
Create a new circular plate frequency tuning study using Protocol 10.

This script creates a complete study configured for intelligent multi-strategy
optimization (IMSO) to test the self-tuning framework.
"""

import json
import shutil
from pathlib import Path

# Study configuration
STUDY_NAME = "circular_plate_frequency_tuning_intelligent_optimizer"
BASE_DIR = Path(__file__).parent
STUDIES_DIR = BASE_DIR / "studies"
STUDY_DIR = STUDIES_DIR / STUDY_NAME

# Source model files (copy from examples)
SOURCE_MODEL_DIR = BASE_DIR / "examples" / "Models" / "Circular Plate"

def create_study_structure():
    """Create complete study directory structure."""
    print(f"Creating study: {STUDY_NAME}")

    # Create directories
    setup_dir = STUDY_DIR / "1_setup"
    model_dir = setup_dir / "model"
    results_dir = STUDY_DIR / "2_results"
    reports_dir = STUDY_DIR / "3_reports"

    for directory in [setup_dir, model_dir, results_dir, reports_dir]:
        directory.mkdir(parents=True, exist_ok=True)
        print(f"  Created: {directory.relative_to(BASE_DIR)}")

    return setup_dir, model_dir, results_dir, reports_dir


def copy_model_files(model_dir):
    """Copy model files from examples."""
    print("\nCopying model files...")

    model_files = [
        "Circular_Plate.prt",
        "Circular_Plate_sim1.sim",
        "Circular_Plate_fem1.fem",
        "Circular_Plate_fem1_i.prt"
    ]

    for filename in model_files:
        source = SOURCE_MODEL_DIR / filename
        dest = model_dir / filename

        if source.exists():
            shutil.copy2(source, dest)
            print(f"  Copied: {filename}")
        else:
            print(f"  WARNING: Source not found: {filename}")

    return list(model_dir.glob("*"))


def create_workflow_config(setup_dir):
    """Create workflow configuration."""
    print("\nCreating workflow configuration...")

    workflow = {
        "study_name": STUDY_NAME,
        "optimization_request": "Tune the first natural frequency mode to exactly 115 Hz using intelligent multi-strategy optimization",
        "design_variables": [
            {
                "parameter": "inner_diameter",
                "bounds": [50, 150],
                "units": "mm",
                "description": "Inner diameter of circular plate"
            },
            {
                "parameter": "plate_thickness",
                "bounds": [2, 10],
                "units": "mm",
                "description": "Thickness of circular plate"
            }
        ],
        "objectives": [
            {
                "name": "frequency_error",
                "goal": "minimize",
                "extraction": {
                    "action": "extract_first_natural_frequency",
                    "params": {
                        "mode_number": 1,
                        "target_frequency": 115.0
                    }
                }
            }
        ],
        "constraints": [
            {
                "name": "frequency_tolerance",
                "type": "less_than",
                "threshold": 0.1,
                "description": "Error from target must be less than 0.1 Hz"
            }
        ]
    }

    workflow_file = setup_dir / "workflow_config.json"
    with open(workflow_file, 'w', encoding='utf-8') as f:
        json.dump(workflow, f, indent=2)

    print(f"  Saved: {workflow_file.relative_to(BASE_DIR)}")
    return workflow


def create_optimization_config(setup_dir):
    """Create Protocol 10 optimization configuration."""
    print("\nCreating Protocol 10 optimization configuration...")

    config = {
        "_description": "Protocol 10: Intelligent Multi-Strategy Optimization - Circular Plate Test",
        "_version": "1.0",

        "study_name": STUDY_NAME,
        "direction": "minimize",

        "intelligent_optimization": {
            "_description": "Protocol 10 - Automatic landscape analysis and strategy selection",
            "enabled": True,

            "characterization_trials": 15,
            "stagnation_window": 10,
            "min_improvement_threshold": 0.001,
            "min_analysis_trials": 10,
            "reanalysis_interval": 15,

            "strategy_preferences": {
                "prefer_cmaes_for_smooth": True,
                "prefer_tpe_for_multimodal": True,
                "enable_hybrid_strategies": False
            }
        },

        "sampler": {
            "_description": "Fallback sampler if Protocol 10 disabled",
            "type": "TPESampler",
            "params": {
                "n_startup_trials": 10,
                "n_ei_candidates": 24,
                "multivariate": True,
                "warn_independent_sampling": True
            }
        },

        "pruner": {
            "type": "MedianPruner",
            "params": {
                "n_startup_trials": 5,
                "n_warmup_steps": 0
            }
        },

        "adaptive_strategy": {
            "_description": "Protocol 8 - Adaptive exploitation based on surrogate confidence",
            "enabled": True,
            "min_confidence_for_exploitation": 0.65,
            "min_trials_for_confidence": 15,
            "target_confidence_metrics": {
                "convergence_weight": 0.4,
                "coverage_weight": 0.3,
                "stability_weight": 0.3
            }
        },

        "trials": {
            "n_trials": 100,
            "timeout": None,
            "catch": []
        },

        "reporting": {
            "auto_generate_plots": True,
            "include_optuna_visualizations": True,
            "include_confidence_report": True,
            "include_strategy_performance": True,
            "save_intelligence_report": True
        },

        "verbosity": {
            "print_landscape_report": True,
            "print_strategy_recommendation": True,
            "print_phase_transitions": True,
            "print_confidence_updates": True,
            "log_to_file": True
        },

        "optimization_notes": "Protocol 10 Test: Atomizer will automatically characterize the circular plate problem, select the best optimization algorithm (TPE, CMA-ES, or GP-BO), and adapt strategy if stagnation is detected. Expected: smooth_unimodal landscape → CMA-ES recommendation."
    }

    config_file = setup_dir / "optimization_config.json"
    with open(config_file, 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=2)

    print(f"  Saved: {config_file.relative_to(BASE_DIR)}")
    return config


def create_runner_script(study_dir, workflow, config):
    """Create optimization runner using Protocol 10."""
    print("\nCreating Protocol 10 optimization runner...")

    runner_code = '''"""
Intelligent Multi-Strategy Optimization Runner
Study: circular_plate_frequency_tuning_intelligent_optimizer

This runner uses Protocol 10 (IMSO) to automatically:
1. Characterize the optimization landscape
2. Select the best optimization algorithm
3. Adapt strategy dynamically if needed

Generated: 2025-11-19
Protocol: 10 (Intelligent Multi-Strategy Optimization)
"""

import sys
import json
import optuna
from pathlib import Path

# Add optimization engine to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from optimization_engine.core.intelligent_optimizer import IntelligentOptimizer
from optimization_engine.nx.updater import NXParameterUpdater
from optimization_engine.nx.solver import NXSolver
from optimization_engine.extractors.frequency_extractor import extract_first_frequency
from optimization_engine.reporting.markdown_report import generate_markdown_report


def main():
    """Run Protocol 10 intelligent optimization."""

    # Setup paths
    study_dir = Path(__file__).parent
    setup_dir = study_dir / "1_setup"
    model_dir = setup_dir / "model"
    results_dir = study_dir / "2_results"
    reports_dir = study_dir / "3_reports"

    # Create directories
    results_dir.mkdir(exist_ok=True)
    reports_dir.mkdir(exist_ok=True)

    # Load configuration
    print("\\nLoading configuration...")
    with open(setup_dir / "workflow_config.json") as f:
        workflow = json.load(f)

    with open(setup_dir / "optimization_config.json") as f:
        opt_config = json.load(f)

    print(f"Study: {workflow['study_name']}")
    print(f"Protocol 10: {opt_config['intelligent_optimization']['enabled']}")

    # Model files
    prt_file = model_dir / "Circular_Plate.prt"
    sim_file = model_dir / "Circular_Plate_sim1.sim"

    # Initialize NX components
    updater = NXParameterUpdater(str(prt_file))
    solver = NXSolver()

    # Incremental history tracking
    history_file = results_dir / "optimization_history_incremental.json"
    history = []

    def objective(trial):
        """Objective function for optimization."""

        # Sample design variables
        inner_diameter = trial.suggest_float('inner_diameter', 50, 150)
        plate_thickness = trial.suggest_float('plate_thickness', 2, 10)

        params = {
            'inner_diameter': inner_diameter,
            'plate_thickness': plate_thickness
        }

        print(f"\\n  Trial #{trial.number}")
        print(f"    Inner Diameter: {inner_diameter:.4f} mm")
        print(f"    Plate Thickness: {plate_thickness:.4f} mm")

        # Update CAD model
        updater.update_expressions(params)

        # Run simulation (use discovered solution name from benchmarking)
        result = solver.run_simulation(str(sim_file), solution_name="Solution_Normal_Modes")

        if not result['success']:
            print(f"    Simulation FAILED: {result.get('error', 'Unknown error')}")
            raise optuna.TrialPruned()

        # Extract frequency
        op2_file = result['op2_file']
        frequency = extract_first_frequency(op2_file, mode_number=1)

        # Calculate objective (error from target)
        target_frequency = 115.0
        objective_value = abs(frequency - target_frequency)

        print(f"    Frequency: {frequency:.4f} Hz")
        print(f"    Target: {target_frequency:.4f} Hz")
        print(f"    Error: {objective_value:.4f} Hz")

        # Save to incremental history
        trial_data = {
            "trial_number": trial.number,
            "design_variables": params,
            "results": {"first_frequency": frequency},
            "objective": objective_value
        }

        history.append(trial_data)

        with open(history_file, 'w', encoding='utf-8') as f:
            json.dump(history, f, indent=2)

        return objective_value

    # Create intelligent optimizer
    print("\\n" + "="*70)
    print("  PROTOCOL 10: INTELLIGENT MULTI-STRATEGY OPTIMIZATION")
    print("="*70)

    optimizer = IntelligentOptimizer(
        study_name=workflow['study_name'],
        study_dir=results_dir,
        config=opt_config,
        verbose=True
    )

    # Extract design variable bounds
    design_vars = {
        var['parameter']: tuple(var['bounds'])
        for var in workflow['design_variables']
    }

    # Run optimization
    results = optimizer.optimize(
        objective_function=objective,
        design_variables=design_vars,
        n_trials=opt_config['trials']['n_trials'],
        target_value=115.0,
        tolerance=0.1
    )

    # Save intelligence report
    optimizer.save_intelligence_report()

    # Generate markdown report
    print("\\nGenerating optimization report...")

    # Load study for Optuna visualizations
    storage = f"sqlite:///{results_dir / 'study.db'}"
    study = optuna.load_study(
        study_name=workflow['study_name'],
        storage=storage
    )

    report = generate_markdown_report(
        history_file=history_file,
        target_value=115.0,
        tolerance=0.1,
        reports_dir=reports_dir,
        study=study
    )

    report_file = reports_dir / "OPTIMIZATION_REPORT.md"
    with open(report_file, 'w', encoding='utf-8') as f:
        f.write(report)

    print(f"\\nReport saved: {report_file}")

    # Print final summary
    print("\\n" + "="*70)
    print("  PROTOCOL 10 TEST COMPLETE")
    print("="*70)
    print(f"Best Frequency: {results['best_value'] + 115.0:.4f} Hz")
    print(f"Best Error: {results['best_value']:.4f} Hz")
    print(f"Best Parameters:")
    for param, value in results['best_params'].items():
        print(f"  {param}: {value:.4f}")

    if 'landscape_analysis' in results and results['landscape_analysis'].get('ready'):
        landscape = results['landscape_analysis']
        print(f"\\nLandscape Type: {landscape['landscape_type'].upper()}")
        print(f"Recommended Strategy: {results.get('final_strategy', 'N/A').upper()}")

    print("="*70)


if __name__ == "__main__":
    main()
'''

    runner_file = study_dir / "run_optimization.py"
    with open(runner_file, 'w', encoding='utf-8') as f:
        f.write(runner_code)

    print(f"  Saved: {runner_file.relative_to(BASE_DIR)}")
    return runner_file


def create_readme(study_dir):
    """Create README for the study."""
    print("\nCreating README...")

    readme = f"""# {STUDY_NAME}

**Protocol 10 Test Study** - Intelligent Multi-Strategy Optimization

## Overview

This study tests Atomizer's Protocol 10 (IMSO) framework on a circular plate frequency tuning problem.

**Goal**: Tune first natural frequency to exactly 115 Hz

**Protocol 10 Features Tested**:
- Automatic landscape characterization (smoothness, multimodality, correlation)
- Intelligent strategy selection (TPE, CMA-ES, or GP-BO)
- Dynamic strategy switching based on stagnation detection
- Comprehensive decision logging for transparency

## Expected Behavior

### Stage 1: Landscape Characterization (Trials 1-15)
- Random exploration to gather data
- Analyze problem characteristics
- Expected classification: `smooth_unimodal` with strong parameter correlation

### Stage 2: Strategy Selection (Trial 15)
- Expected recommendation: **CMA-ES** (92% confidence)
- Reasoning: "Smooth unimodal with strong correlation - CMA-ES converges quickly"

### Stage 3: Adaptive Optimization (Trials 16-100)
- Run with CMA-ES sampler
- Monitor for stagnation
- Switch strategies if needed (unlikely for this problem)

## Study Structure

```
{STUDY_NAME}/
├── 1_setup/
│   ├── model/                    # CAD and simulation files
│   ├── workflow_config.json      # Optimization goals
│   └── optimization_config.json  # Protocol 10 configuration
├── 2_results/
│   ├── study.db                  # Optuna database
│   ├── optimization_history_incremental.json
│   └── intelligent_optimizer/    # Protocol 10 tracking
│       ├── strategy_transitions.json
│       ├── strategy_performance.json
│       └── intelligence_report.json
└── 3_reports/
    └── OPTIMIZATION_REPORT.md    # Final report with visualizations
```

## Running the Optimization

```bash
# Activate environment
conda activate test_env

# Run optimization
python run_optimization.py
```

## What to Look For

### Console Output

**Landscape Analysis Report**:
```
======================================================================
  LANDSCAPE ANALYSIS REPORT
======================================================================
  Type: SMOOTH_UNIMODAL
  Smoothness: 0.7X (smooth)
  Multimodal: NO (1 modes)
  Parameter Correlation: 0.6X (strong)
```

**Strategy Recommendation**:
```
======================================================================
  STRATEGY RECOMMENDATION
======================================================================
  Recommended: CMAES
  Confidence: 92.0%
  Reasoning: Smooth unimodal with strong correlation - CMA-ES converges quickly
```

**Phase Transitions** (if any):
```
======================================================================
  STRATEGY TRANSITION
======================================================================
  Trial #45
  TPE → CMAES
  Reason: Stagnation detected
```

### Intelligence Report

Check `2_results/intelligent_optimizer/intelligence_report.json` for:
- Complete landscape analysis
- Strategy recommendation reasoning
- All transition events
- Performance breakdown by strategy

### Optimization Report

Check `3_reports/OPTIMIZATION_REPORT.md` for:
- Best result (should be < 0.1 Hz error)
- Convergence plots
- Optuna visualizations
- (Future: Protocol 10 analysis section)

## Expected Results

**Baseline (TPE only)**: ~160 trials to achieve 0.18 Hz error

**Protocol 10 (Intelligent)**: ~60-80 trials to achieve < 0.1 Hz error

**Improvement**: 40-50% faster convergence by selecting optimal algorithm

## Configuration

See [`optimization_config.json`](1_setup/optimization_config.json) for full Protocol 10 settings.

Key parameters:
- `characterization_trials`: 15 (initial exploration)
- `stagnation_window`: 10 (trials to check for stagnation)
- `min_improvement_threshold`: 0.001 (0.1% minimum improvement)

## References

- [PROTOCOL.md](../../PROTOCOL.md) - Complete Protocol 10 documentation
- [Protocol 10 Implementation Summary](../../docs/PROTOCOL_10_IMPLEMENTATION_SUMMARY.md)
- [Example Configuration](../../examples/optimization_config_protocol10.json)

---

*Study created: 2025-11-19*
*Protocol: 10 (Intelligent Multi-Strategy Optimization)*
"""

    readme_file = study_dir / "README.md"
    with open(readme_file, 'w', encoding='utf-8') as f:
        f.write(readme)

    print(f"  Saved: {readme_file.relative_to(BASE_DIR)}")


def main():
    """Create complete Protocol 10 test study."""
    print("\n" + "="*70)
    print("  CREATING PROTOCOL 10 TEST STUDY")
    print("="*70)

    # Create structure
    setup_dir, model_dir, results_dir, reports_dir = create_study_structure()

    # Copy model files
    model_files = copy_model_files(model_dir)

    # Create configurations
    workflow = create_workflow_config(setup_dir)
    config = create_optimization_config(setup_dir)

    # Create runner
    runner_file = create_runner_script(STUDY_DIR, workflow, config)

    # Create README
    create_readme(STUDY_DIR)

    print("\n" + "="*70)
    print("  STUDY CREATION COMPLETE")
    print("="*70)
    print(f"\nStudy directory: {STUDY_DIR.relative_to(BASE_DIR)}")
    print(f"\nTo run optimization:")
    print(f"  cd {STUDY_DIR.relative_to(BASE_DIR)}")
    print(f"  python run_optimization.py")
    print("\n" + "="*70)


if __name__ == "__main__":
    main()
