import os
from macer.defaults import DEFAULT_MODELS, _macer_root, resolve_model_path, DEFAULT_SEVENNET_MODAL
from macer.utils.model_manager import ensure_model, print_model_help

_SEVENNET_AVAILABLE = False
try:
    from sevenn.calculator import SevenNetCalculator
    _SEVENNET_AVAILABLE = True
except Exception as e:
    import traceback
    _SEVENNET_ERR = f"{e}\n{traceback.format_exc()}"
    pass

def get_sevennet_calculator(model_path: str, device: str = "cpu", modal: str = None):
    """Construct SevenNet calculator."""
    if not _SEVENNET_AVAILABLE:
        if '_SEVENNET_ERR' in globals():
            print(f"ERROR DETAILS: {_SEVENNET_ERR}")
        raise RuntimeError("SevenNet related libraries are not installed. Please reinstall with 'pip install macer'.")

    # Use default modal from config if not specified
    if modal is None:
        modal = DEFAULT_SEVENNET_MODAL

    # Display available SevenNet tasks and fidelities
    sevennet_tasks = {
        "mpa": "PBE(+U)",
        "omat24": "PBE(+U)",
        "matpes_pbe": "PBE",
        "oc20": "RPBE",
        "oc22": "PBE(+U)",
        "odac23": "PBE-D3",
        "omol25_low": "ωB97M-V",
        "omol25_high": "ωB97M-V*",
        "spice": "ωB97M",
        "qcml": "PBE0",
        "pet_mad": "PBEsol",
        "mp_r2scan": "r²SCAN",
        "matpes_r2scan": "r²SCAN"
    }

    print("\nList of available SevenNet tasks and corresponding fidelities:")
    print(f"{'Task name':<15} | {'Fidelity':<15}")
    print("-" * 33)
    for task, fidelity in sevennet_tasks.items():
        print(f"{task:<15} | {fidelity:<15}")
    
    print(f"\n>>> Selected SevenNet modal: {modal}")

    if model_path is None:
        # Use the default SevenNet model path from DEFAULT_MODELS
        default_sevennet_model_name = DEFAULT_MODELS.get("sevennet")
        if default_sevennet_model_name:
            # Check and Provision
            ensure_model("sevennet", default_sevennet_model_name)
            model_path = resolve_model_path(default_sevennet_model_name)
            print(f"No specific SevenNet model path provided; using default: {model_path}")
        else:
            raise ValueError("No default SevenNet model specified in default-model.yaml and no model_path provided.")
    else:
        # Check if the file exists. If not, try to auto-provision.
        if not os.path.exists(model_path):
            basename = os.path.basename(model_path)
            provisioned = ensure_model("sevennet", basename)
            if provisioned:
                model_path = provisioned
            else:
                # Provisioning failed or model unknown
                print_model_help("sevennet")
                raise FileNotFoundError(f"Model file not found: {model_path}")
        
        # If it was a relative path and exists (or was just provisioned), resolve it to absolute if needed
        if not os.path.isabs(model_path):
             model_path = resolve_model_path(model_path)

    calc_args = {
        "model": model_path,
        "device": device,
    }
    if modal:
        calc_args["modal"] = modal

    return SevenNetCalculator(**calc_args)
