from __future__ import annotations

import shutil
from pathlib import Path

import pytest

from file_safeguard.processor import BatchConfig, BatchProcessor


def make_processor(tmp_path: Path, policy: str = "skip") -> tuple[BatchProcessor, Path, Path]:
    source, output = tmp_path / "输入", tmp_path / "输出"
    source.mkdir()
    return BatchProcessor(BatchConfig(source, output, suffix_tag="_清理", collision_policy=policy)), source, output


def test_empty_directory_is_a_valid_preview(tmp_path: Path) -> None:
    processor, _, _ = make_processor(tmp_path)
    report = processor.run()
    assert report.processed == 0 and report.plans == []


def test_chinese_path_and_output_verification(tmp_path: Path) -> None:
    processor, source, output = make_processor(tmp_path)
    (source / "订单 一.csv").write_text("name,amount\n畅畅,8\n", encoding="utf-8")
    report = processor.run(dry_run=False)
    assert report.processed == 1
    assert (output / "订单 一_清理.csv").read_text(encoding="utf-8").endswith("畅畅,8\n")
    assert (source / "订单 一.csv").exists()


def test_duplicate_is_skipped_and_original_is_unchanged(tmp_path: Path) -> None:
    processor, source, _ = make_processor(tmp_path)
    (source / "a.txt").write_text("same", encoding="utf-8")
    (source / "b.txt").write_text("same", encoding="utf-8")
    report = processor.run()
    assert len([plan for plan in report.plans if plan.status == "skip"]) == 1
    assert (source / "a.txt").read_text(encoding="utf-8") == "same"


def test_version_policy_never_overwrites(tmp_path: Path) -> None:
    processor, source, output = make_processor(tmp_path, "version")
    (source / "a.txt").write_text("new", encoding="utf-8")
    output.mkdir()
    (output / "a_清理.txt").write_text("old", encoding="utf-8")
    report = processor.run(dry_run=False)
    assert report.processed == 1
    assert (output / "a_清理_v2.txt").read_text(encoding="utf-8") == "new"
    assert (output / "a_清理.txt").read_text(encoding="utf-8") == "old"


def test_invalid_encoding_becomes_error(tmp_path: Path) -> None:
    processor, source, _ = make_processor(tmp_path)
    (source / "bad.txt").write_bytes(b"\xff\xfe")
    report = processor.run()
    assert report.failed == 1
    assert report.plans[0].status == "error"


def test_insufficient_space_stops_before_output(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    processor, source, output = make_processor(tmp_path)
    (source / "a.txt").write_text("safe", encoding="utf-8")
    usage = shutil.disk_usage(tmp_path)
    monkeypatch.setattr(shutil, "disk_usage", lambda _: usage.__class__(usage.total, 0, 0))
    with pytest.raises(OSError, match="Insufficient disk space"):
        processor.run(dry_run=False)
    assert not (output / "a_清理.txt").exists()


def test_cancel_leaves_no_final_file(tmp_path: Path) -> None:
    processor, source, output = make_processor(tmp_path)
    (source / "a.txt").write_text("large enough", encoding="utf-8")
    report = processor.run(dry_run=False, should_cancel=lambda: True)
    assert report.cancelled is True
    assert not any(output.iterdir()) if output.exists() else True


def test_repeated_run_skips_existing_output(tmp_path: Path) -> None:
    processor, source, output = make_processor(tmp_path)
    (source / "a.txt").write_text("repeat", encoding="utf-8")
    assert processor.run(dry_run=False).processed == 1
    assert processor.run(dry_run=False).skipped == 1
    assert (output / "a_清理.txt").read_text(encoding="utf-8") == "repeat"
