import pytest
from pydantic import ValidationError

from control_backend.schemas.program import (
    Goal,
    KeywordTrigger,
    Norm,
    Phase,
    Program,
    TriggerKeyword,
)


def base_norm() -> Norm:
    return Norm(
        id="norm1",
        label="testNorm",
        norm="testNormNorm",
    )


def base_goal() -> Goal:
    return Goal(
        id="goal1",
        label="testGoal",
        description="testGoalDescription",
        achieved=False,
    )


def base_trigger() -> KeywordTrigger:
    return KeywordTrigger(
        id="trigger1",
        label="testTrigger",
        type="keywords",
        keywords=[
            TriggerKeyword(id="keyword1", keyword="testKeyword1"),
            TriggerKeyword(id="keyword1", keyword="testKeyword2"),
        ],
    )


def base_phase() -> Phase:
    return Phase(
        id="phase1",
        label="basephase",
        norms=[base_norm()],
        goals=[base_goal()],
        triggers=[base_trigger()],
    )


def base_program() -> Program:
    return Program(phases=[base_phase()])


def invalid_program() -> dict:
    # wrong types inside phases list (not Phase objects)
    return {
        "phases": [
            {"id": "phase1"},  # incomplete
            {"not_a_phase": True},
        ]
    }


def test_valid_program():
    program = base_program()
    validated = Program.model_validate(program)
    assert isinstance(validated, Program)
    assert validated.phases[0].norms[0].norm == "testNormNorm"


def test_valid_deepprogram():
    program = base_program()
    validated = Program.model_validate(program)
    # validate nested components directly
    phase = validated.phases[0]
    assert isinstance(phase.goals[0], Goal)
    assert isinstance(phase.triggers[0], KeywordTrigger)
    assert isinstance(phase.norms[0], Norm)


def test_invalid_program():
    bad = invalid_program()
    with pytest.raises(ValidationError):
        Program.model_validate(bad)
