"""Tests for the FileScanner module."""

from __future__ import annotations

import hashlib
from pathlib import Path

from scanner.manifest import TrackManifestCollection
from scanner.scanner import FileScanner, calculate_sha256


def _create_audio_file(path: Path, content: bytes = b"fake audio") -> None:
    """Create a file with the given content in a temporary directory.

    Args:
        path: Full path to the file to create.
        content: Bytes to write into the file.
    """
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_bytes(content)


def test_calculate_sha256(tmp_path: Path) -> None:
    """Verify that SHA-256 is calculated correctly."""
    file_path = tmp_path / "test.wav"
    content = b"hello world"
    _create_audio_file(file_path, content)

    expected = hashlib.sha256(content).hexdigest()
    result = calculate_sha256(file_path)
    assert result == expected


def test_recursive_scanning(tmp_path: Path) -> None:
    """Verify that the scanner finds files in nested directories."""
    _create_audio_file(tmp_path / "top.wav")
    _create_audio_file(tmp_path / "album" / "track.flac")
    _create_audio_file(tmp_path / "album" / "sub" / "deep.aiff")

    scanner = FileScanner(music_directory=tmp_path)
    collection = scanner.scan()

    assert len(collection) == 3
    paths = collection.paths
    assert "top.wav" in paths
    assert "album/track.flac" in paths
    assert "album/sub/deep.aiff" in paths


def test_supported_formats(tmp_path: Path) -> None:
    """Verify that all supported formats are discovered."""
    for ext in (".wav", ".flac", ".aiff", ".aif"):
        _create_audio_file(tmp_path / f"track{ext}")

    scanner = FileScanner(music_directory=tmp_path)
    collection = scanner.scan()

    assert len(collection) == 4


def test_unsupported_formats_ignored(tmp_path: Path) -> None:
    """Verify that unsupported file extensions are ignored."""
    _create_audio_file(tmp_path / "song.wav")
    _create_audio_file(tmp_path / "song.mp3")
    _create_audio_file(tmp_path / "song.ogg")
    _create_audio_file(tmp_path / "readme.txt")

    scanner = FileScanner(music_directory=tmp_path)
    collection = scanner.scan()

    assert len(collection) == 1
    assert collection.find_by_path("song.wav") is not None


def test_duplicate_detection(tmp_path: Path) -> None:
    """Verify that duplicate files (same SHA-256) are detected."""
    content = b"identical content"
    _create_audio_file(tmp_path / "original.wav", content)
    _create_audio_file(tmp_path / "copy.wav", content)

    scanner = FileScanner(music_directory=tmp_path)
    collection = scanner.scan()

    assert len(collection) == 2
    duplicates = collection.get_duplicates()
    assert len(duplicates) == 1


def test_sha256_correctness(tmp_path: Path) -> None:
    """Verify that the scanner produces correct SHA-256 hashes."""
    content = b"test audio data"
    _create_audio_file(tmp_path / "track.wav", content)

    scanner = FileScanner(music_directory=tmp_path)
    collection = scanner.scan()

    manifest = collection.find_by_path("track.wav")
    assert manifest is not None
    expected_hash = hashlib.sha256(content).hexdigest()
    assert manifest.sha256 == expected_hash


def test_empty_directory(tmp_path: Path) -> None:
    """Verify that scanning an empty directory returns an empty collection."""
    scanner = FileScanner(music_directory=tmp_path)
    collection = scanner.scan()

    assert isinstance(collection, TrackManifestCollection)
    assert len(collection) == 0


def test_nonexistent_directory(tmp_path: Path) -> None:
    """Verify that scanning a non-existent directory returns empty."""
    scanner = FileScanner(music_directory=tmp_path / "nonexistent")
    collection = scanner.scan()

    assert len(collection) == 0


def test_file_size_recorded(tmp_path: Path) -> None:
    """Verify that file size is correctly recorded in the manifest."""
    content = b"x" * 5000
    _create_audio_file(tmp_path / "big.wav", content)

    scanner = FileScanner(music_directory=tmp_path)
    collection = scanner.scan()

    manifest = collection.find_by_path("big.wav")
    assert manifest is not None
    assert manifest.file_size == 5000
