"""Unit tests for commit engine."""

from __future__ import annotations

from pathlib import Path

from cascade_fm.commit import ConflictPolicy, commit_operation_output
from cascade_fm.operations.base import CommitIntent


def test_commit_materialized_outputs_copies_files(tmp_path: Path) -> None:
    """Materialized operation outputs are copied to target directory."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    output_file = source_dir / "image.png"
    output_file.write_text("data")

    result = commit_operation_output(
        commit_intent=CommitIntent.MATERIALIZED_OUTPUTS,
        source_files=[],
        output_files=[output_file],
        target_dir=target_dir,
    )

    assert result.committed == 1
    assert result.failed == 0
    assert result.skipped == 0
    assert (target_dir / "image.png").read_text() == "data"


def test_commit_materialized_outputs_uses_conflict_safe_name(tmp_path: Path) -> None:
    """Commit creates unique target names when destination already exists."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    (target_dir / "photo.jpg").write_text("old")
    output_file = source_dir / "photo.jpg"
    output_file.write_text("new")

    result = commit_operation_output(
        commit_intent=CommitIntent.MATERIALIZED_OUTPUTS,
        source_files=[],
        output_files=[output_file],
        target_dir=target_dir,
    )

    assert result.committed == 1
    assert result.failed == 0
    assert result.skipped == 0
    assert (target_dir / "photo.jpg").read_text() == "old"
    assert (target_dir / "photo_1.jpg").read_text() == "new"


def test_commit_materialized_outputs_overwrite_policy(tmp_path: Path) -> None:
    """Overwrite policy replaces existing target file in place."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    (target_dir / "photo.jpg").write_text("old")
    output_file = source_dir / "photo.jpg"
    output_file.write_text("new")

    result = commit_operation_output(
        commit_intent=CommitIntent.MATERIALIZED_OUTPUTS,
        source_files=[],
        output_files=[output_file],
        target_dir=target_dir,
        conflict_policy=ConflictPolicy.OVERWRITE,
    )

    assert result.committed == 1
    assert result.failed == 0
    assert result.skipped == 0
    assert (target_dir / "photo.jpg").read_text() == "new"
    assert not (target_dir / "photo_1.jpg").exists()


def test_commit_materialized_outputs_skip_policy(tmp_path: Path) -> None:
    """Skip policy keeps existing target and skips conflicting file."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    (target_dir / "photo.jpg").write_text("old")
    output_file = source_dir / "photo.jpg"
    output_file.write_text("new")

    result = commit_operation_output(
        commit_intent=CommitIntent.MATERIALIZED_OUTPUTS,
        source_files=[],
        output_files=[output_file],
        target_dir=target_dir,
        conflict_policy=ConflictPolicy.SKIP,
    )

    assert result.committed == 0
    assert result.failed == 0
    assert result.skipped == 1
    assert (target_dir / "photo.jpg").read_text() == "old"
    assert not (target_dir / "photo_1.jpg").exists()


def test_commit_rename_planned_paths_uses_output_names(tmp_path: Path) -> None:
    """Rename commit copies source files using planned output names."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    source_a = source_dir / "a.txt"
    source_b = source_dir / "b.txt"
    source_a.write_text("A")
    source_b.write_text("B")

    planned_a = source_dir / "01_alpha.txt"
    planned_b = source_dir / "02_beta.txt"

    result = commit_operation_output(
        commit_intent=CommitIntent.PLANNED_OUTPUT_NAMES,
        source_files=[source_a, source_b],
        output_files=[planned_a, planned_b],
        target_dir=target_dir,
    )

    assert result.committed == 2
    assert result.failed == 0
    assert result.skipped == 0
    assert (target_dir / "01_alpha.txt").read_text() == "A"
    assert (target_dir / "02_beta.txt").read_text() == "B"


def test_commit_rename_planned_paths_overwrite_policy(tmp_path: Path) -> None:
    """Overwrite policy replaces existing planned rename target."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    source_a = source_dir / "a.txt"
    source_a.write_text("A")
    planned_a = source_dir / "01_alpha.txt"
    (target_dir / "01_alpha.txt").write_text("OLD")

    result = commit_operation_output(
        commit_intent=CommitIntent.PLANNED_OUTPUT_NAMES,
        source_files=[source_a],
        output_files=[planned_a],
        target_dir=target_dir,
        conflict_policy=ConflictPolicy.OVERWRITE,
    )

    assert result.committed == 1
    assert result.failed == 0
    assert result.skipped == 0
    assert (target_dir / "01_alpha.txt").read_text() == "A"


def test_commit_rename_planned_paths_skip_policy(tmp_path: Path) -> None:
    """Skip policy leaves existing planned rename target untouched."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    source_a = source_dir / "a.txt"
    source_a.write_text("A")
    planned_a = source_dir / "01_alpha.txt"
    (target_dir / "01_alpha.txt").write_text("OLD")

    result = commit_operation_output(
        commit_intent=CommitIntent.PLANNED_OUTPUT_NAMES,
        source_files=[source_a],
        output_files=[planned_a],
        target_dir=target_dir,
        conflict_policy=ConflictPolicy.SKIP,
    )

    assert result.committed == 0
    assert result.failed == 0
    assert result.skipped == 1
    assert (target_dir / "01_alpha.txt").read_text() == "OLD"


def test_commit_rename_reports_mismatch_failures(tmp_path: Path) -> None:
    """Rename commit marks unmatched source/planned pairs as failures."""
    source_dir = tmp_path / "source"
    target_dir = tmp_path / "target"
    source_dir.mkdir()
    target_dir.mkdir()

    source_a = source_dir / "a.txt"
    source_b = source_dir / "b.txt"
    source_a.write_text("A")
    source_b.write_text("B")

    planned_a = source_dir / "01_alpha.txt"

    result = commit_operation_output(
        commit_intent=CommitIntent.PLANNED_OUTPUT_NAMES,
        source_files=[source_a, source_b],
        output_files=[planned_a],
        target_dir=target_dir,
    )

    assert result.committed == 1
    assert result.failed == 1
    assert result.skipped == 0
    assert (target_dir / "01_alpha.txt").read_text() == "A"


def test_commit_none_intent_reports_no_writes(tmp_path: Path) -> None:
    """NONE intent should not commit output artifacts."""
    target_dir = tmp_path / "target"
    target_dir.mkdir()

    source = tmp_path / "source.txt"
    source.write_text("data")

    result = commit_operation_output(
        commit_intent=CommitIntent.NONE,
        source_files=[source],
        output_files=[source],
        target_dir=target_dir,
    )

    assert result.committed == 0
    assert result.failed == 1
    assert result.skipped == 0
    assert not (target_dir / "source.txt").exists()
