from workouts.models import (
    Exercise,
    WorkoutLogData,
    WorkoutRoutine,
    WorkoutSetEntry,
)
from workouts.utils import (
    display_value,
    display_weight,
    kg_to_lbs,
    lbs_to_kg,
    normalize_weight,
)


class TestWeightUtils:
    def test_lbs_to_kg(self):
        assert lbs_to_kg(1) == 0.45
        assert lbs_to_kg(100) == 45.36

    def test_kg_to_lbs(self):
        assert kg_to_lbs(1) == 2.2
        assert kg_to_lbs(45.36) == 100.0

    def test_normalize_weight_metric(self):
        assert normalize_weight("50", "metric") == 50.0

    def test_normalize_weight_imperial(self):
        assert normalize_weight("45", "imperial") == lbs_to_kg(45)

    def test_normalize_weight_empty(self):
        assert normalize_weight("", "metric") is None
        assert normalize_weight(None, "metric") is None

    def test_display_value(self):
        assert display_value(50, "metric") == 50.0
        assert display_value(45.36, "imperial") == 100.0

    def test_display_weight(self):
        assert display_weight(50, "metric") == "50.0 kg"
        assert display_weight(45.36, "imperial") == "100.0 lbs"


class TestExerciseModel:
    def test_str(self, exercise):
        assert str(exercise) == "Deadlift"

    def test_find_or_create(self, exercise):
        found = Exercise.find_or_create("deadlift")
        assert found.id == exercise.id
        new = Exercise.find_or_create("New Exercise")
        assert new.id != exercise.id


class TestWorkoutRoutineModel:
    def test_media_type_label(self, workout_routine):
        assert workout_routine.media_type_label == "Workout"

    def test_find_or_create(self, workout_routine):
        found = WorkoutRoutine.find_or_create("test routine")
        assert found.id == workout_routine.id

    def test_logdata_cls(self, workout_routine):
        assert workout_routine.logdata_cls is WorkoutLogData


class TestWorkoutLogData:
    def test_as_html_metric(self, workout_scrobble, exercise):
        html = workout_scrobble.logdata.as_html()
        assert "Deadlift" in html
        assert "3 x 10" in html
        assert "50.0 kg" in html

    def test_as_html_imperial(self, workout_scrobble, exercise):
        html = workout_scrobble.logdata.as_html(units="imperial")
        assert "110.2 lbs" in html

    def test_workout_list(self, workout_scrobble):
        assert "Deadlift" in workout_scrobble.logdata.workout_list

    def test_from_log_dict_roundtrip(self, workout_scrobble):
        log_dict = workout_scrobble.log
        data = WorkoutLogData.from_log_dict(log_dict)
        assert (
            data["workouts"][0]["exercise_id"]
            == workout_scrobble.log["workouts"][0]["exercise_id"]
        )
        restored = WorkoutLogData(**data)
        assert restored.workouts[0]["sets"] == 3
        assert restored.workouts[0]["weight_kg"] == 50.0
        entry = WorkoutSetEntry(**restored.workouts[0])
        assert entry.sets == 3
        assert entry.weight_kg == 50.0

    def test_override_fields(self):
        fields = WorkoutLogData.override_fields()
        assert "workouts" in fields
        assert "with_people_ids" in fields

    def test_prepare_form_metric(self, logdata):
        form = WorkoutLogData.form()()
        WorkoutLogData.prepare_form(form, "metric")
        assert form.fields["workouts"].units == "metric"
        assert form.fields["bodyweight_kg"].label == "Bodyweight (kg)"

    def test_prepare_form_imperial(self, logdata):
        form = WorkoutLogData.form()()
        WorkoutLogData.prepare_form(form, "imperial")
        assert form.fields["workouts"].units == "imperial"
        assert form.fields["bodyweight_kg"].label == "Bodyweight (lbs)"

    def test_normalize_form_data_imperial(self, logdata):
        data = {"bodyweight_kg": 180.5}
        WorkoutLogData.normalize_form_data(data, "imperial")
        assert data["bodyweight_kg"] == lbs_to_kg(180.5)

    def test_normalize_form_data_metric_no_change(self, logdata):
        data = {"bodyweight_kg": 80.0}
        WorkoutLogData.normalize_form_data(data, "metric")
        assert data["bodyweight_kg"] == 80.0
