import json
import os
import tarfile
import tempfile

import pytest
from workouts.importer import (
    _find_root,
    _image_paths_for,
    import_wrkout_exercises,
    load_exercises_data,
)
from workouts.models import Exercise

SAMPLE_EXERCISE = {
    "name": "3/4 Sit-Up",
    "force": "pull",
    "level": "beginner",
    "mechanic": "compound",
    "equipment": "body only",
    "primaryMuscles": ["abdominals"],
    "secondaryMuscles": [],
    "instructions": ["Lie down.", "Sit up."],
    "category": "strength",
}


@pytest.fixture
def sample_tarball():
    with tempfile.NamedTemporaryFile(suffix=".tar.gz", delete=False) as f:
        tarball_path = f.name
    with tempfile.TemporaryDirectory() as src:
        root = os.path.join(src, "exercises.json-master")
        exercise_dir = os.path.join(root, "exercises", "3_4_Sit-Up")
        images_dir = os.path.join(exercise_dir, "images")
        os.makedirs(images_dir)
        with open(os.path.join(exercise_dir, "exercise.json"), "w") as f:
            json.dump(SAMPLE_EXERCISE, f)
        with open(os.path.join(images_dir, "0.jpg"), "wb") as f:
            f.write(b"\xff\xd8\xff\xe0fakejpeg")
        with tarfile.open(tarball_path, "w:gz") as tf:
            for dirpath, dirnames, filenames in os.walk(src):
                for filename in filenames:
                    full = os.path.join(dirpath, filename)
                    arcname = os.path.relpath(full, src)
                    tf.add(full, arcname=arcname)
    return tarball_path


class TestHelpers:
    def test_find_root(self, sample_tarball):
        import tempfile

        dest = tempfile.mkdtemp()
        with tarfile.open(sample_tarball, "r:gz") as tf:
            tf.extractall(dest)
        root = _find_root(dest)
        assert root.endswith("exercises.json-master")

    def test_load_exercises_data(self, sample_tarball):
        import tempfile

        dest = tempfile.mkdtemp()
        with tarfile.open(sample_tarball, "r:gz") as tf:
            tf.extractall(dest)
        root = _find_root(dest)
        data = load_exercises_data(root)
        assert len(data) == 1
        assert data[0]["name"] == "3/4 Sit-Up"
        assert os.path.isdir(data[0]["_dir"])

    def test_image_paths_for(self, sample_tarball):
        import tempfile

        dest = tempfile.mkdtemp()
        with tarfile.open(sample_tarball, "r:gz") as tf:
            tf.extractall(dest)
        root = _find_root(dest)
        data = load_exercises_data(root)
        paths = _image_paths_for(data[0]["_dir"])
        assert len(paths) == 1
        assert paths[0].endswith("0.jpg")


class TestImport:
    def test_import_creates_exercises(self, db, sample_tarball):
        result = import_wrkout_exercises(tarball_path=sample_tarball)
        assert result["created"] == 1
        exercise = Exercise.objects.get(name="3/4 Sit-Up")
        assert exercise.level == "beginner"
        assert exercise.primary_muscles == ["abdominals"]
        assert exercise.instructions == ["Lie down.", "Sit up."]
        assert exercise.photo

    def test_import_dry_run(self, db, sample_tarball):
        result = import_wrkout_exercises(tarball_path=sample_tarball, dry_run=True)
        assert result["created"] == 0
        assert Exercise.objects.count() == 0

    def test_import_no_images(self, db, sample_tarball):
        result = import_wrkout_exercises(
            tarball_path=sample_tarball, import_images=False
        )
        assert result["created"] == 1
        exercise = Exercise.objects.get(name="3/4 Sit-Up")
        assert not exercise.photo

    def test_import_updates_existing(self, db, sample_tarball):
        Exercise.objects.create(name="3/4 Sit-Up", level="beginner")
        result = import_wrkout_exercises(
            tarball_path=sample_tarball, import_images=False
        )
        assert result["created"] == 0
        assert result["updated"] == 1
