import os
import pytest
from unittest.mock import patch, MagicMock
from app.pipeline import video, thumb, storage

import respx
import httpx
from httpx import Response


@pytest.fixture
def tmp_storage(monkeypatch, tmp_path):
    monkeypatch.setattr(storage, "VIDEO_DATA_DIR", str(tmp_path))
    # 더미 입력 파일들
    audio = tmp_path / "audio.mp3"
    audio.write_bytes(b"\x00" * 100)
    cover_dir = tmp_path / "50"
    cover_dir.mkdir()
    cover = cover_dir / "cover.jpg"
    cover.write_bytes(b"\x00" * 100)
    return tmp_path


@patch("subprocess.run")
def test_thumb_extracts_frame(mock_run, tmp_storage):
    mock_run.return_value = MagicMock(returncode=0, stderr="")
    video_path = tmp_storage / "60" / "video.mp4"
    video_path.parent.mkdir()
    video_path.write_bytes(b"\x00" * 100)
    out = thumb.generate(pipeline_id=60, video_path=str(video_path),
                          track_title="Midnight Drive", overlay_text=False)
    assert out["url"].endswith("/60/thumbnail.jpg")
    args = mock_run.call_args[0][0]
    assert args[0] == "ffmpeg"


@patch("subprocess.run")
def test_thumb_failure_raises(mock_run, tmp_storage):
    mock_run.return_value = MagicMock(returncode=1, stderr="bad input")
    video_path = tmp_storage / "61" / "video.mp4"
    video_path.parent.mkdir()
    video_path.write_bytes(b"\x00" * 100)
    with pytest.raises(thumb.ThumbGenerationError):
        thumb.generate(pipeline_id=61, video_path=str(video_path),
                        track_title="X", overlay_text=False)


# ===== Video tests (replacing the FFmpeg-based tests) =====

@pytest.fixture
def encoder_env(monkeypatch):
    monkeypatch.setattr(video, "ENCODER_URL", "http://192.168.45.59:8765")
    monkeypatch.setattr(video, "NAS_VIDEOS_ROOT", "/volume1/docker/webpage/data/videos")
    monkeypatch.setattr(video, "NAS_MUSIC_ROOT", "/volume1/docker/webpage/data/music")


@respx.mock
def test_generate_video_calls_remote_encoder(encoder_env, tmp_path, monkeypatch):
    monkeypatch.setattr(storage, "VIDEO_DATA_DIR", str(tmp_path))
    respx.post("http://192.168.45.59:8765/encode_video").mock(
        return_value=Response(200, json={
            "ok": True, "duration_ms": 12000,
            "output_path_nas": "/volume1/docker/webpage/data/videos/3/video.mp4",
            "output_bytes": 28000000,
            "encoder": "h264_nvenc", "preset": "p4",
        })
    )
    out = video.generate(
        pipeline_id=3,
        audio_path="/app/data/1c695df3.mp3",
        cover_path="/app/data/videos/3/cover.jpg",
        genre="lo-fi", duration_sec=120, resolution="1920x1080",
        style="visualizer",
    )
    assert out["url"].endswith("/3/video.mp4")
    assert out["used_fallback"] is False
    assert out["encode_duration_ms"] == 12000


@respx.mock
def test_generate_video_raises_on_connection_error(encoder_env, monkeypatch, tmp_path):
    monkeypatch.setattr(storage, "VIDEO_DATA_DIR", str(tmp_path))
    respx.post("http://192.168.45.59:8765/encode_video").mock(
        side_effect=httpx.ConnectError("Connection refused")
    )
    with pytest.raises(video.VideoGenerationError) as exc:
        video.generate(
            pipeline_id=4,
            audio_path="/app/data/x.mp3", cover_path="/app/data/videos/4/cover.jpg",
            genre="lo-fi", duration_sec=120, resolution="1920x1080",
        )
    assert "연결 실패" in str(exc.value) or "Connection" in str(exc.value)


@respx.mock
def test_generate_video_raises_on_500(encoder_env, monkeypatch, tmp_path):
    monkeypatch.setattr(storage, "VIDEO_DATA_DIR", str(tmp_path))
    respx.post("http://192.168.45.59:8765/encode_video").mock(
        return_value=Response(500, json={"detail": {"ok": False, "stage": "ffmpeg", "error": "bad codec"}})
    )
    with pytest.raises(video.VideoGenerationError) as exc:
        video.generate(
            pipeline_id=5,
            audio_path="/app/data/x.mp3", cover_path="/app/data/videos/5/cover.jpg",
            genre="lo-fi", duration_sec=120, resolution="1920x1080",
        )
    assert "Windows 인코더 오류" in str(exc.value)
    assert "ffmpeg" in str(exc.value)


def test_generate_video_no_url_configured(monkeypatch, tmp_path):
    monkeypatch.setattr(storage, "VIDEO_DATA_DIR", str(tmp_path))
    monkeypatch.setattr(video, "ENCODER_URL", "")
    with pytest.raises(video.VideoGenerationError) as exc:
        video.generate(
            pipeline_id=6,
            audio_path="/app/data/x.mp3", cover_path="/app/data/videos/6/cover.jpg",
            genre="lo-fi", duration_sec=120, resolution="1920x1080",
        )
    assert "WINDOWS_VIDEO_ENCODER_URL" in str(exc.value)


def test_container_to_nas_videos_path(monkeypatch):
    monkeypatch.setattr(video, "NAS_VIDEOS_ROOT", "/volume1/docker/webpage/data/videos")
    monkeypatch.setattr(video, "NAS_MUSIC_ROOT", "/volume1/docker/webpage/data/music")
    assert video._container_to_nas("/app/data/videos/3/cover.jpg") == "/volume1/docker/webpage/data/videos/3/cover.jpg"


def test_container_to_nas_music_path(monkeypatch):
    monkeypatch.setattr(video, "NAS_VIDEOS_ROOT", "/volume1/docker/webpage/data/videos")
    monkeypatch.setattr(video, "NAS_MUSIC_ROOT", "/volume1/docker/webpage/data/music")
    assert video._container_to_nas("/app/data/abc.mp3") == "/volume1/docker/webpage/data/music/abc.mp3"


def test_container_to_nas_strips_cache_buster(monkeypatch):
    monkeypatch.setattr(video, "NAS_VIDEOS_ROOT", "/volume1/docker/webpage/data/videos")
    monkeypatch.setattr(video, "NAS_MUSIC_ROOT", "/volume1/docker/webpage/data/music")
    # cache-busted path → strip ?v=... before NAS conversion
    assert video._container_to_nas("/app/data/videos/3/cover.jpg?v=20260510065642") == "/volume1/docker/webpage/data/videos/3/cover.jpg"


@respx.mock
def test_generate_video_passes_essential_params(encoder_env, tmp_path, monkeypatch):
    monkeypatch.setattr(storage, "VIDEO_DATA_DIR", str(tmp_path))
    captured = {}

    def hook(req):
        import json as _json
        captured["body"] = _json.loads(req.content)
        return Response(200, json={"ok": True, "duration_ms": 5000,
                                    "output_path_nas": "/v/3/video.mp4",
                                    "output_bytes": 10_000_000,
                                    "encoder": "h264_nvenc", "preset": "p4"})

    respx.post("http://192.168.45.59:8765/encode_video").mock(side_effect=hook)
    out = video.generate(
        pipeline_id=3, audio_path="/app/data/x.mp3",
        cover_path="/app/data/videos/3/cover.jpg",
        genre="mix", duration_sec=3600, resolution="1920x1080",
        style="essential", background_mode="video_loop",
        background_path="/app/data/videos/3/loop.mp4",
        tracks=[{"id": 1, "title": "T1", "start_offset_sec": 0}],
    )
    body = captured["body"]
    assert body["style"] == "essential"
    assert body["background_mode"] == "video_loop"
    assert body["background_path_nas"] == "/volume1/docker/webpage/data/videos/3/loop.mp4"
    assert body["tracks"][0]["title"] == "T1"
    assert out["url"].endswith("/3/video.mp4")
