import os
from pathlib import Path

from core.context_loader import build_context_bundle
from core.models import ContextSource, DecisionPacket, MeetingBrief, MeetingInput


def test_directory_sources_are_sorted_before_truncation(tmp_path: Path) -> None:
    docs_dir = tmp_path / "docs"
    docs_dir.mkdir()
    (docs_dir / "b.md").write_text("B", encoding="utf-8")
    (docs_dir / "a.md").write_text("A", encoding="utf-8")

    meeting_input = MeetingInput(
        topic="topic",
        brief=MeetingBrief(),
        decision_packet=DecisionPacket(decision_to_make="topic"),
        context_sources=[
            ContextSource(
                type="directory",
                path="./docs",
                purpose="docs",
                include=["**/*.md"],
                max_files=1,
            )
        ],
    )

    bundle = build_context_bundle(meeting_input, tmp_path / "meeting.yaml")

    assert bundle.documents[0].source_path.endswith("a.md")


def test_binary_file_is_skipped_with_reason(tmp_path: Path) -> None:
    binary_path = tmp_path / "blob.bin"
    binary_path.write_bytes(b"\x00\x01\x02")

    meeting_input = MeetingInput(
        topic="topic",
        brief=MeetingBrief(),
        decision_packet=DecisionPacket(decision_to_make="topic"),
        context_sources=[
            ContextSource(type="file", path="./blob.bin", purpose="binary")
        ],
    )

    bundle = build_context_bundle(meeting_input, tmp_path / "meeting.yaml")

    assert bundle.documents == []
    assert bundle.skipped_paths[0]["reason"] == "binary"


def test_symlink_is_skipped_with_reason(tmp_path: Path) -> None:
    target = tmp_path / "target.md"
    target.write_text("hello", encoding="utf-8")
    link = tmp_path / "link.md"
    link.symlink_to(target)

    meeting_input = MeetingInput(
        topic="topic",
        brief=MeetingBrief(),
        decision_packet=DecisionPacket(decision_to_make="topic"),
        context_sources=[
            ContextSource(type="file", path="./link.md", purpose="link")
        ],
    )

    bundle = build_context_bundle(meeting_input, tmp_path / "meeting.yaml")

    assert bundle.documents == []
    assert bundle.skipped_paths[0]["reason"] == "symlink"


def test_unreadable_file_is_skipped_with_reason(tmp_path: Path) -> None:
    path = tmp_path / "secret.md"
    path.write_text("hidden", encoding="utf-8")
    path.chmod(0)

    try:
        meeting_input = MeetingInput(
            topic="topic",
            brief=MeetingBrief(),
            decision_packet=DecisionPacket(decision_to_make="topic"),
            context_sources=[
                ContextSource(type="file", path="./secret.md", purpose="secret")
            ],
        )

        bundle = build_context_bundle(meeting_input, tmp_path / "meeting.yaml")
    finally:
        path.chmod(0o644)

    assert bundle.documents == []
    assert bundle.skipped_paths[0]["reason"] == "unreadable"


def test_utf8_replacement_behavior_preserves_document(tmp_path: Path) -> None:
    path = tmp_path / "bad.txt"
    path.write_bytes(b"valid\xfftext")

    meeting_input = MeetingInput(
        topic="topic",
        brief=MeetingBrief(),
        decision_packet=DecisionPacket(decision_to_make="topic"),
        context_sources=[
            ContextSource(type="file", path="./bad.txt", purpose="text")
        ],
    )

    bundle = build_context_bundle(meeting_input, tmp_path / "meeting.yaml")

    assert len(bundle.documents) == 1
    assert "valid" in bundle.documents[0].excerpt


def test_skipped_paths_include_path_and_reason(tmp_path: Path) -> None:
    path = tmp_path / "blob.bin"
    path.write_bytes(b"\x00\x01")

    meeting_input = MeetingInput(
        topic="topic",
        brief=MeetingBrief(),
        decision_packet=DecisionPacket(decision_to_make="topic"),
        context_sources=[ContextSource(type="file", path="./blob.bin", purpose="binary")],
    )

    bundle = build_context_bundle(meeting_input, tmp_path / "meeting.yaml")

    assert set(bundle.skipped_paths[0]) == {"path", "reason"}


def test_document_ids_do_not_collide_for_flat_and_nested_paths(tmp_path: Path) -> None:
    (tmp_path / "a__b.md").write_text("flat", encoding="utf-8")
    nested_dir = tmp_path / "a"
    nested_dir.mkdir()
    (nested_dir / "b.md").write_text("nested", encoding="utf-8")

    meeting_input = MeetingInput(
        topic="topic",
        brief=MeetingBrief(),
        decision_packet=DecisionPacket(decision_to_make="topic"),
        context_sources=[
            ContextSource(type="directory", path=".", purpose="docs", include=["**/*.md"])
        ],
    )

    bundle = build_context_bundle(meeting_input, tmp_path / "meeting.yaml")
    document_ids = [document.document_id for document in bundle.documents]

    assert len(document_ids) == len(set(document_ids))
