import pytest
from unittest.mock import patch, MagicMock
from app.pipeline.orchestrator import _resolve_input


def test_resolve_input_track():
    pipeline = {"id": 1, "track_id": 13, "compile_job_id": None}
    track = {
        "id": 13, "title": "Lo-Fi Drive", "genre": "lo-fi",
        "moods": ["chill"], "duration_sec": 176,
        "file_path": "/app/data/x.mp3", "audio_url": "/media/music/x.mp3",
    }
    with patch("app.pipeline.orchestrator.db.get_track_by_id", return_value=track):
        result = _resolve_input(pipeline)
    assert result["audio_path"] == "/app/data/x.mp3"
    assert result["duration_sec"] == 176
    assert len(result["tracks"]) == 1
    assert result["tracks"][0]["start_offset_sec"] == 0
    assert result["title"] == "Lo-Fi Drive"
    assert result["genre"] == "lo-fi"


def test_resolve_input_compile_job():
    pipeline = {"id": 2, "track_id": None, "compile_job_id": 5}
    job = {
        "id": 5, "status": "succeeded", "title": "Chill Mix",
        "audio_path": "/app/data/compiles/5.mp3",
        "track_ids": [13, 14, 15],
        "crossfade_sec": 3,
    }
    tracks = {
        13: {"id": 13, "title": "T1", "duration_sec": 180},
        14: {"id": 14, "title": "T2", "duration_sec": 200},
        15: {"id": 15, "title": "T3", "duration_sec": 150},
    }
    with patch("app.pipeline.orchestrator.db.get_compile_job", return_value=job), \
         patch("app.pipeline.orchestrator.db.get_track_by_id", side_effect=lambda i: tracks[i]):
        result = _resolve_input(pipeline)
    assert result["audio_path"] == "/app/data/compiles/5.mp3"
    # 누적 = 180+200+150 - 2*3(crossfade pair gaps) = 524
    assert result["duration_sec"] == 524
    assert len(result["tracks"]) == 3
    assert result["tracks"][0]["start_offset_sec"] == 0
    assert result["tracks"][1]["start_offset_sec"] == 177  # 180 - 3
    assert result["tracks"][2]["start_offset_sec"] == 374  # 177 + 200 - 3
    assert result["title"] == "Chill Mix"
    assert result["genre"] == "mix"


def test_resolve_input_compile_not_ready():
    pipeline = {"id": 3, "track_id": None, "compile_job_id": 6}
    job = {"id": 6, "status": "rendering"}
    with patch("app.pipeline.orchestrator.db.get_compile_job", return_value=job):
        with pytest.raises(ValueError, match="not ready"):
            _resolve_input(pipeline)


def test_resolve_input_neither():
    pipeline = {"id": 4, "track_id": None, "compile_job_id": None}
    with pytest.raises(ValueError):
        _resolve_input(pipeline)


def test_resolve_input_compile_job_done_status():
    """compile job status='done'도 accept (production convention)."""
    pipeline = {"id": 5, "track_id": None, "compile_job_id": 7}
    job = {
        "id": 7, "status": "done", "title": "Done Mix",
        "audio_path": "/app/data/compiles/7.mp3",
        "track_ids": [1], "crossfade_sec": 0,
    }
    track = {"id": 1, "title": "T1", "duration_sec": 100}
    with patch("app.pipeline.orchestrator.db.get_compile_job", return_value=job), \
         patch("app.pipeline.orchestrator.db.get_track_by_id", return_value=track):
        result = _resolve_input(pipeline)
    assert result["audio_path"] == "/app/data/compiles/7.mp3"
    assert result["title"] == "Done Mix"


def test_local_path_strips_cache_buster():
    from app.pipeline.orchestrator import _local_path
    # /media/videos/3/cover.jpg?v=... → /app/data/videos/3/cover.jpg
    assert _local_path("/media/videos/3/cover.jpg?v=20260510065642") == "/app/data/videos/3/cover.jpg"
