import pytest
import sys
from unittest.mock import MagicMock, patch

# Mock hardware modules before importing wecker (tests run off the Pi).
sys.modules["RPi"] = MagicMock()
sys.modules["RPi.GPIO"] = MagicMock()
sys.modules["pygame"] = MagicMock()

import common  # noqa: E402
import wecker  # noqa: E402


@pytest.fixture
def mock_pid_file(tmp_path):
    """Provides a temporary PID file path and resets the lock fd."""
    pid_file = tmp_path / "wecker.pid"
    with patch("wecker.PID_FILE", str(pid_file)):
        wecker._pid_lock_fd = None
        yield pid_file
        if wecker._pid_lock_fd is not None:
            try:
                wecker._pid_lock_fd.close()
            except OSError:
                pass
            wecker._pid_lock_fd = None


def test_ensure_single_instance_success(mock_pid_file):
    """Test that the script can start if no other instance holds the lock."""
    with patch("os.getpid", return_value=1234):
        wecker.ensure_single_instance()

    assert mock_pid_file.read_text() == "1234"


def test_ensure_single_instance_already_running(mock_pid_file):
    """Test that the script exits if another instance holds the lock."""
    with patch("fcntl.flock", side_effect=BlockingIOError), pytest.raises(
        SystemExit
    ) as excinfo:
        wecker.ensure_single_instance()

    assert excinfo.value.code == 1


def test_ensure_single_instance_overwrites_stale_pid(mock_pid_file):
    """Test that a stale PID file is overwritten once the lock is acquired."""
    mock_pid_file.write_text("5678")

    with patch("os.getpid", return_value=1234):
        wecker.ensure_single_instance()

    assert mock_pid_file.read_text() == "1234"


def test_remove_pid_file_success(mock_pid_file):
    """Test that remove_pid_file closes the lock and removes the file."""
    with patch("os.getpid", return_value=1234):
        wecker.ensure_single_instance()

    wecker.remove_pid_file()
    assert not mock_pid_file.exists()


def test_pid_file_defined_once_across_modules():
    """DRY principle: PID_FILE must be defined in common.py and imported."""
    assert wecker.PID_FILE is common.PID_FILE, (
        "wecker.PID_FILE must reference common.PID_FILE, not redefine it"
    )
    assert common.PID_FILE.endswith("wecker.pid")
