"""
Test: Complete Optimization with Journal-Based NX Solver

This tests the complete workflow:
1. Update model parameters in .prt
2. Solve via journal (using running NX GUI)
3. Extract results from OP2
4. Run optimization loop

REQUIREMENTS:
- Simcenter3D must be open (but no files need to be loaded)
- test_env conda environment activated
"""

from pathlib import Path
import sys

# Add project root to path so we can import atomizer_paths
sys.path.insert(0, str(Path(__file__).parent.parent))

# Use intelligent path resolution
import atomizer_paths
atomizer_paths.ensure_imports()

from optimization_engine.core.runner import OptimizationRunner
from optimization_engine.nx.updater import update_nx_model
from optimization_engine.nx.solver import run_nx_simulation
from optimization_engine.result_extractors.extractors import (
    stress_extractor,
    displacement_extractor
)


# Global variable to store current design variables for the simulation runner
_current_design_vars = {}


def bracket_model_updater(design_vars: dict):
    """
    Store design variables for the simulation runner.

    Note: We no longer directly update the .prt file here.
    Instead, design variables are passed to the journal which applies them in NX.
    """
    global _current_design_vars
    _current_design_vars = design_vars.copy()

    print(f"\n[MODEL UPDATE] Design variables prepared")
    for name, value in design_vars.items():
        print(f"  {name} = {value:.4f}")


def bracket_simulation_runner() -> Path:
    """
    Run NX solver via journal on running NX GUI session.

    This connects to the running Simcenter3D GUI and:
    1. Opens the .sim file
    2. Applies expression updates in the journal
    3. Updates geometry and FEM
    4. Solves the simulation
    5. Returns path to .op2 file
    """
    global _current_design_vars
    sim_file = atomizer_paths.studies() / "bracket_stress_minimization/model/Bracket_sim1.sim"

    print("\n[SIMULATION] Running via journal on NX GUI...")
    print(f"  SIM file: {sim_file.name}")
    if _current_design_vars:
        print(f"  Expression updates: {_current_design_vars}")

    try:
        # Run solver via journal (connects to running NX GUI)
        # Pass expression updates directly to the journal
        op2_file = run_nx_simulation(
            sim_file=sim_file,
            nastran_version="2412",
            timeout=300,  # 5 minute timeout
            cleanup=True,  # Clean up temp files
            use_journal=True,  # Use journal mode (requires NX GUI open)
            expression_updates=_current_design_vars  # Pass design vars to journal
        )

        print(f"[SIMULATION] Complete! Results: {op2_file.name}")
        return op2_file

    except Exception as e:
        print(f"[SIMULATION] FAILED: {e}")
        raise


if __name__ == "__main__":
    print("="*60)
    print("JOURNAL-BASED OPTIMIZATION TEST")
    print("="*60)
    print("\nREQUIREMENTS:")
    print("- Simcenter3D must be OPEN (no files need to be loaded)")
    print("- Will run 50 optimization trials (~3-4 minutes)")
    print("- Strategy: 20 random trials (exploration) + 30 TPE trials (exploitation)")
    print("- Each trial: update params -> solve via journal -> extract results")
    print("="*60)

    response = input("\nIs Simcenter3D open? (yes/no): ")
    if response.lower() not in ['yes', 'y']:
        print("Please open Simcenter3D and try again.")
        sys.exit(0)

    config_path = atomizer_paths.studies() / "bracket_stress_minimization/optimization_config_stress_displacement.json"

    runner = OptimizationRunner(
        config_path=config_path,
        model_updater=bracket_model_updater,
        simulation_runner=bracket_simulation_runner,  # Journal-based solver!
        result_extractors={
            'stress_extractor': stress_extractor,
            'displacement_extractor': displacement_extractor
        }
    )

    # Use the configured number of trials (50 by default)
    n_trials = runner.config['optimization_settings']['n_trials']

    # Check for existing studies
    existing_studies = runner.list_studies()

    print("\n" + "="*60)
    print("STUDY MANAGEMENT")
    print("="*60)

    if existing_studies:
        print(f"\nFound {len(existing_studies)} existing studies:")
        for study in existing_studies:
            print(f"  - {study['study_name']}: {study.get('total_trials', 0)} trials")

        print("\nOptions:")
        print("1. Create NEW study (fresh start)")
        print("2. RESUME existing study (add more trials)")
        choice = input("\nChoose option (1 or 2): ").strip()

        if choice == '2':
            # Resume existing study
            if len(existing_studies) == 1:
                study_name = existing_studies[0]['study_name']
                print(f"\nResuming study: {study_name}")
            else:
                print("\nAvailable studies:")
                for i, study in enumerate(existing_studies):
                    print(f"{i+1}. {study['study_name']}")
                study_idx = int(input("Select study number: ")) - 1
                study_name = existing_studies[study_idx]['study_name']

            resume_mode = True
        else:
            # New study
            study_name = input("\nEnter study name (default: bracket_stress_opt): ").strip()
            if not study_name:
                study_name = "bracket_stress_opt"
            resume_mode = False
    else:
        print("\nNo existing studies found. Creating new study.")
        study_name = input("\nEnter study name (default: bracket_stress_opt): ").strip()
        if not study_name:
            study_name = "bracket_stress_opt"
        resume_mode = False

    print("\n" + "="*60)
    if resume_mode:
        print(f"RESUMING STUDY: {study_name}")
        print(f"Adding {n_trials} additional trials")
    else:
        print(f"STARTING NEW STUDY: {study_name}")
        print(f"Running {n_trials} trials")
    print("="*60)
    print("Objective: Minimize max von Mises stress")
    print("Constraint: Max displacement <= 1.0 mm")
    print("Solver: Journal-based (using running NX GUI)")
    print(f"Sampler: TPE (20 random startup + {n_trials-20} TPE)")
    print("="*60)

    try:
        study = runner.run(
            study_name=study_name,
            n_trials=n_trials,
            resume=resume_mode
        )

        print("\n" + "="*60)
        print("OPTIMIZATION COMPLETE!")
        print("="*60)
        print(f"\nBest stress: {study.best_value:.2f} MPa")
        print(f"\nBest parameters:")
        for param, value in study.best_params.items():
            print(f"  {param}: {value:.4f}")

        print(f"\nResults saved to: {runner.output_dir}")
        print("\nCheck history.csv to see optimization progress!")

    except Exception as e:
        print(f"\n{'='*60}")
        print("ERROR DURING OPTIMIZATION")
        print("="*60)
        print(f"{e}")
        import traceback
        traceback.print_exc()
        print("\nMake sure:")
        print("  - Simcenter3D is open and running")
        print("  - .sim file is valid and solvable")
        print("  - No other processes are locking the files")
