"""Tests for noisegate.program — load, save, resolve."""

from pathlib import Path

import pytest
import yaml

import noisegate.config as config_module
from noisegate.exceptions import ProgramParseError
from noisegate.models import Program
from noisegate.program import load_program, resolve_program, save_program

FIXTURE_DIR = Path(__file__).parent / "fixtures"
ACME_YAML = FIXTURE_DIR / "acme.yaml"


# ---------------------------------------------------------------------------
# resolve_program
# ---------------------------------------------------------------------------

def test_resolve_program_short_name():
    result = resolve_program("acme")
    assert result == config_module._PROGRAMS_DIR / "acme.yaml"


def test_resolve_program_absolute_path():
    path = "/abs/path/to/foo.yaml"
    result = resolve_program(path)
    assert result == Path(path)


def test_resolve_program_relative_with_separator(tmp_path):
    rel = str(tmp_path / "foo.yaml")
    result = resolve_program(rel)
    assert result == Path(rel)


# ---------------------------------------------------------------------------
# load_program
# ---------------------------------------------------------------------------

def test_load_fixture():
    program = load_program(ACME_YAML)
    assert program.name == "Acme Bug Bounty Program"
    assert program.platform == "HackerOne"
    assert program.source == "https://example.com/security"
    assert "*.acme.com" in program.assets.include
    assert "community.acme.com" in program.assets.exclude
    assert len(program.ineligible_findings) == 3
    assert len(program.required_report_sections) == 3
    assert len(program.notes) == 2


def test_load_program_malformed_yaml(tmp_path):
    bad = tmp_path / "bad.yaml"
    bad.write_text("name: [unclosed bracket")
    with pytest.raises(ProgramParseError):
        load_program(bad)


def test_load_program_missing_required_field(tmp_path):
    missing_name = tmp_path / "missing.yaml"
    missing_name.write_text(yaml.dump({"platform": "HackerOne", "source": "https://example.com"}))
    with pytest.raises(ProgramParseError):
        load_program(missing_name)


def test_load_program_empty_lists_valid(tmp_path):
    minimal = tmp_path / "minimal.yaml"
    minimal.write_text(yaml.dump({
        "name": "Minimal Program",
        "platform": "Bugcrowd",
        "source": "https://bugcrowd.com/minimal",
    }))
    program = load_program(minimal)
    assert program.ineligible_findings == []
    assert program.required_report_sections == []
    assert program.notes == []
    assert program.assets.include == []
    assert program.assets.exclude == []


# ---------------------------------------------------------------------------
# save_program + round-trip
# ---------------------------------------------------------------------------

def test_round_trip(tmp_path):
    original = load_program(ACME_YAML)
    out_path = tmp_path / "acme_out.yaml"
    save_program(original, out_path)
    reloaded = load_program(out_path)
    assert reloaded == original


def test_save_creates_parent_dirs(tmp_path):
    program = Program(
        name="Test",
        platform="HackerOne",
        source="https://hackerone.com/test",
    )
    deep = tmp_path / "a" / "b" / "c" / "test.yaml"
    save_program(program, deep)
    assert deep.exists()
    reloaded = load_program(deep)
    assert reloaded.name == "Test"
