"""Script codegen: generate standalone TrainingJob Python scripts."""

from __future__ import annotations

from typing import Any


def generate_training_script(config: dict[str, Any], data_path: str) -> str:
    """Generate a self-contained Python training script.

    The generated script uses ``from haute.modelling import TrainingJob``
    and can be run standalone, used as a Databricks Job, or modified for
    experimentation.

    Parameters
    ----------
    config : dict
        Modelling node configuration containing algorithm, target, weight,
        exclude, params, split, metrics, mlflow_experiment, model_name,
        loss_function, variance_power, offset, monotone_constraints,
        feature_weights, cv_folds, etc.
    data_path : str
        Path to the training data file (e.g. "output/frequency.parquet").

    Returns
    -------
    str
        Complete Python script as a string.
    """
    name = config.get("name", "model")
    target = config.get("target", "")
    weight = config.get("weight")
    exclude = config.get("exclude", [])
    algorithm = config.get("algorithm", "catboost")
    task = config.get("task", "regression")
    params = config.get("params", {})
    split = config.get("split", {"strategy": "random", "test_size": 0.2, "seed": 42})
    metrics = config.get("metrics", ["gini", "rmse"])
    mlflow_experiment = config.get("mlflow_experiment")
    model_name = config.get("model_name")
    output_dir = config.get("output_dir", "models")
    loss_function = config.get("loss_function")
    variance_power = config.get("variance_power")
    offset = config.get("offset")
    monotone_constraints = config.get("monotone_constraints")
    feature_weights = config.get("feature_weights")
    cv_folds = config.get("cv_folds")

    parts: list[str] = [
        '"""Training script generated by Haute."""',
        "",
        "from haute.modelling import TrainingJob",
        "",
        "",
        "job = TrainingJob(",
        f'    name={name!r},',
        f'    data={data_path!r},',
        f'    target={target!r},',
    ]

    if weight:
        parts.append(f'    weight={weight!r},')
    if exclude:
        parts.append(f'    exclude={exclude!r},')

    parts.append(f'    algorithm={algorithm!r},')
    parts.append(f'    task={task!r},')

    if params:
        parts.append(f'    params={params!r},')

    parts.append(f'    split={split!r},')
    parts.append(f'    metrics={metrics!r},')

    if loss_function:
        parts.append(f'    loss_function={loss_function!r},')
    if variance_power is not None and loss_function == "Tweedie":
        parts.append(f'    variance_power={variance_power!r},')
    if offset:
        parts.append(f'    offset={offset!r},')
    if monotone_constraints:
        parts.append(f'    monotone_constraints={monotone_constraints!r},')
    if feature_weights:
        parts.append(f'    feature_weights={feature_weights!r},')
    if cv_folds:
        parts.append(f'    cv_folds={cv_folds!r},')

    if mlflow_experiment:
        parts.append(f'    mlflow_experiment={mlflow_experiment!r},')
    if model_name:
        parts.append(f'    model_name={model_name!r},')

    parts.append(f'    output_dir={output_dir!r},')
    parts.append(")")
    parts.append("")
    parts.append("")
    parts.append('if __name__ == "__main__":')
    parts.append("    result = job.run()")
    parts.append('    print(f"Model saved to: {result.model_path}")')
    parts.append("    for name, value in result.metrics.items():")
    parts.append('        print(f"  {name}: {value:.4f}")')
    parts.append("")

    return "\n".join(parts)
