"""Tests for the TrackImporter module."""

from __future__ import annotations

from pathlib import Path

from conftest import init_test_db
from database.models import TrackStatus
from database.repositories import TrackRepository
from importer.importer import ImportResult, TrackImporter
from scanner.manifest import TrackManifest, TrackManifestCollection


def _make_manifest(
    relative_path: str,
    sha256: str,
    file_size: int = 100,
) -> TrackManifest:
    """Create a TrackManifest for testing.

    Args:
        relative_path: Relative path for the manifest.
        sha256: SHA-256 hash.
        file_size: File size in bytes.

    Returns:
        A :class:`TrackManifest` instance.
    """
    return TrackManifest(
        relative_path=relative_path,
        original_filename=relative_path.split("/")[-1],
        file_size=file_size,
        sha256=sha256,
    )


def test_import_new_tracks(tmp_path: Path) -> None:
    """Verify that new tracks are imported into the database."""
    session = init_test_db(tmp_path)
    try:
        collection = TrackManifestCollection(
            [
                _make_manifest("a.wav", "hash1"),
                _make_manifest("b.wav", "hash2"),
            ]
        )

        result = TrackImporter.import_manifests(session, collection)

        assert result.new_tracks == 2
        assert result.duplicates == 0
        assert result.modified == 0
        assert result.deleted == 0
        assert result.unchanged == 0
    finally:
        session.close()


def test_import_duplicate_detection(tmp_path: Path) -> None:
    """Verify that duplicate hashes are detected and not imported twice."""
    session = init_test_db(tmp_path)
    try:
        collection = TrackManifestCollection(
            [
                _make_manifest("original.wav", "shared_hash"),
                _make_manifest("copy.wav", "shared_hash"),
            ]
        )

        result = TrackImporter.import_manifests(session, collection)

        assert result.new_tracks == 1
        assert result.duplicates == 1
    finally:
        session.close()


def test_import_modified_file_not_overwritten(tmp_path: Path) -> None:
    """Verify that modified files are reported but not overwritten."""
    session = init_test_db(tmp_path)
    try:
        first_collection = TrackManifestCollection(
            [_make_manifest("song.wav", "original_hash")]
        )
        TrackImporter.import_manifests(session, first_collection)

        second_collection = TrackManifestCollection(
            [_make_manifest("song.wav", "modified_hash")]
        )
        result = TrackImporter.import_manifests(session, second_collection)

        assert result.modified == 1
        assert result.new_tracks == 0

        track = TrackRepository.find_by_path(session, "song.wav")
        assert track is not None
        assert track.sha256 == "original_hash"
    finally:
        session.close()


def test_import_deleted_track_marked_missing(tmp_path: Path) -> None:
    """Verify that deleted tracks are marked as MISSING."""
    session = init_test_db(tmp_path)
    try:
        first_collection = TrackManifestCollection(
            [_make_manifest("song.wav", "hash1")]
        )
        TrackImporter.import_manifests(session, first_collection)

        empty_collection = TrackManifestCollection([])
        result = TrackImporter.import_manifests(session, empty_collection)

        assert result.deleted == 1

        track = TrackRepository.find_by_path(session, "song.wav")
        assert track is not None
        assert track.status == TrackStatus.MISSING
    finally:
        session.close()


def test_import_unchanged_tracks(tmp_path: Path) -> None:
    """Verify that unchanged tracks are counted correctly."""
    session = init_test_db(tmp_path)
    try:
        collection = TrackManifestCollection([_make_manifest("song.wav", "hash1")])
        TrackImporter.import_manifests(session, collection)

        result = TrackImporter.import_manifests(session, collection)

        assert result.unchanged == 1
        assert result.new_tracks == 0
    finally:
        session.close()


def test_import_default_project_created(tmp_path: Path) -> None:
    """Verify that a default project is created automatically."""
    session = init_test_db(tmp_path)
    try:
        collection = TrackManifestCollection([_make_manifest("song.wav", "hash1")])
        TrackImporter.import_manifests(session, collection)

        from database.repositories import DEFAULT_PROJECT_NAME, ProjectRepository

        project = ProjectRepository.get_default_project(session)
        assert project.name == DEFAULT_PROJECT_NAME
    finally:
        session.close()


def test_import_result_is_frozen() -> None:
    """Verify that ImportResult is immutable."""
    result = ImportResult(
        new_tracks=1,
        duplicates=0,
        modified=0,
        deleted=0,
        unchanged=0,
    )
    try:
        result.new_tracks = 5
        raise AssertionError("Should have raised FrozenInstanceError")
    except Exception:
        pass


def test_import_mixed_scenario(tmp_path: Path) -> None:
    """Verify a mixed scenario with new, unchanged, modified, and deleted tracks."""
    session = init_test_db(tmp_path)
    try:
        first = TrackManifestCollection(
            [
                _make_manifest("keep.wav", "hash_keep"),
                _make_manifest("modify.wav", "hash_modify_old"),
                _make_manifest("delete.wav", "hash_delete"),
            ]
        )
        TrackImporter.import_manifests(session, first)

        second = TrackManifestCollection(
            [
                _make_manifest("keep.wav", "hash_keep"),
                _make_manifest("modify.wav", "hash_modify_new"),
                _make_manifest("new.wav", "hash_new"),
            ]
        )
        result = TrackImporter.import_manifests(session, second)

        assert result.new_tracks == 1
        assert result.unchanged == 1
        assert result.modified == 1
        assert result.deleted == 1

        deleted_track = TrackRepository.find_by_path(session, "delete.wav")
        assert deleted_track is not None
        assert deleted_track.status == TrackStatus.MISSING

        modified_track = TrackRepository.find_by_path(session, "modify.wav")
        assert modified_track is not None
        assert modified_track.sha256 == "hash_modify_old"
    finally:
        session.close()
