from __future__ import annotations

import json
from pathlib import Path

import pytest

from screenshot._shared.cli.parser import load_cli_inputs
from screenshot._shared.cli.schema import ScreenshotCliArgs


def _build_args(input_path: Path) -> ScreenshotCliArgs:
    return ScreenshotCliArgs(
        input=input_path,
        urls=(),
        site_ids=(),
        partition_date=None,
        max_pages=1,
        depth=0,
        viewports=("desktop",),
        post_nav_wait_s=0.0,
        timeout_s=30.0,
        max_retries=None,
        job_budget_s=None,
    )


def test_load_cli_inputs_rejects_non_object_jsonl_line(tmp_path: Path) -> None:
    input_path = tmp_path / "jobs.jsonl"
    input_path.write_text("[]\n", encoding="utf-8")

    with pytest.raises(ValueError, match=r"jobs\.jsonl:1: expected JSON object"):
        load_cli_inputs(_build_args(input_path))


def test_load_cli_inputs_requires_non_empty_url_with_line_number(tmp_path: Path) -> None:
    input_path = tmp_path / "jobs.jsonl"
    input_path.write_text(json.dumps({"job_id": "demo", "url": "   "}) + "\n", encoding="utf-8")

    with pytest.raises(ValueError, match=r"jobs\.jsonl:1: missing non-empty 'url'"):
        load_cli_inputs(_build_args(input_path))


def test_load_cli_inputs_rejects_non_string_url(tmp_path: Path) -> None:
    input_path = tmp_path / "jobs.jsonl"
    input_path.write_text(json.dumps({"job_id": "demo", "url": False}) + "\n", encoding="utf-8")

    with pytest.raises(ValueError, match=r"jobs\.jsonl:1: 'url' must be a string"):
        load_cli_inputs(_build_args(input_path))


def test_load_cli_inputs_rejects_legacy_html_snapshot_field(tmp_path: Path) -> None:
    input_path = tmp_path / "jobs.jsonl"
    input_path.write_text(
        json.dumps({"job_id": "demo", "url": "https://example.com", "html_snapshot_path": False})
        + "\n",
        encoding="utf-8",
    )

    with pytest.raises(
        ValueError,
        match=r"jobs\.jsonl:1: 'html_snapshot_path' is no longer supported",
    ):
        load_cli_inputs(_build_args(input_path))


def test_load_cli_inputs_parses_nested_artifacts(tmp_path: Path) -> None:
    input_path = tmp_path / "jobs.jsonl"
    input_path.write_text(
        json.dumps(
            {
                "job_id": "demo",
                "url": "https://example.com",
                "artifacts": {
                    "html_snapshot": {"path": "out/page.html"},
                    "motion_snapshot": {"path": "out/page.gif", "duration_s": 2.0, "fps": 4},
                },
            }
        )
        + "\n",
        encoding="utf-8",
    )

    records, _, _ = load_cli_inputs(_build_args(input_path))

    assert records[0].artifacts.html_snapshot is not None
    assert records[0].artifacts.html_snapshot.path == Path("out/page.html")
    assert records[0].artifacts.motion_snapshot is not None
    assert records[0].artifacts.motion_snapshot.path == Path("out/page.gif")
    assert records[0].artifacts.motion_snapshot.duration_s == 2.0
    assert records[0].artifacts.motion_snapshot.fps == 4


@pytest.mark.parametrize(
    ("field", "value", "error"),
    [
        ("duration_s", 0.0, "motion snapshot duration_s must be > 0"),
        ("fps", 0, "motion snapshot fps must be >= 1"),
    ],
)
def test_load_cli_inputs_rejects_invalid_motion_snapshot_numeric_values(
    tmp_path: Path,
    field: str,
    value: object,
    error: str,
) -> None:
    input_path = tmp_path / "jobs.jsonl"
    input_path.write_text(
        json.dumps(
            {
                "job_id": "demo",
                "url": "https://example.com",
                "artifacts": {
                    "motion_snapshot": {
                        "path": "out/page.gif",
                        field: value,
                    }
                },
            }
        )
        + "\n",
        encoding="utf-8",
    )

    with pytest.raises(ValueError, match=error):
        load_cli_inputs(_build_args(input_path))


def test_load_cli_inputs_requires_nested_option_objects(tmp_path: Path) -> None:
    input_path = tmp_path / "jobs.jsonl"
    input_path.write_text(
        json.dumps({"job_id": "demo", "url": "https://example.com", "options": []}) + "\n",
        encoding="utf-8",
    )

    with pytest.raises(ValueError, match=r"jobs\.jsonl:1: 'options' must be an object"):
        load_cli_inputs(_build_args(input_path))
