#!/usr/bin/env python3
"""utils/interrupt.py 테스트 스위트"""

import signal
import sys
import threading
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from utils.interrupt import INTERRUPT, InterruptFlag, register_signal_handler


class TestInterruptFlag:
    """InterruptFlag 클래스 단위 테스트"""

    def test_initial_state_is_not_set(self):
        """생성 직후 is_set()은 False"""
        flag = InterruptFlag()
        assert flag.is_set() is False

    def test_set_makes_is_set_true(self):
        """set() 호출 후 is_set()은 True"""
        flag = InterruptFlag()
        flag.set()
        assert flag.is_set() is True

    def test_reset_clears_flag(self):
        """reset() 호출 후 is_set()은 False"""
        flag = InterruptFlag()
        flag.set()
        flag.reset()
        assert flag.is_set() is False

    def test_set_is_idempotent(self):
        """set()을 여러 번 호출해도 True 유지"""
        flag = InterruptFlag()
        flag.set()
        flag.set()
        assert flag.is_set() is True

    def test_reset_without_set(self):
        """set() 없이 reset() 해도 오류 없음"""
        flag = InterruptFlag()
        flag.reset()  # should not raise
        assert flag.is_set() is False

    def test_thread_safety(self):
        """멀티 스레드에서 set/reset 안전"""
        flag = InterruptFlag()
        errors: list[Exception] = []

        def worker():
            try:
                for _ in range(100):
                    flag.set()
                    flag.is_set()
                    flag.reset()
            except Exception as e:
                errors.append(e)

        threads = [threading.Thread(target=worker) for _ in range(5)]
        for t in threads:
            t.start()
        for t in threads:
            t.join()

        assert len(errors) == 0


class TestGlobalInterrupt:
    """글로벌 INTERRUPT 인스턴스 테스트"""

    def setup_method(self):
        INTERRUPT.reset()

    def test_global_instance_exists(self):
        """INTERRUPT 글로벌 인스턴스가 InterruptFlag 타입"""
        assert isinstance(INTERRUPT, InterruptFlag)

    def test_global_instance_initially_not_set(self):
        """초기 상태는 미설정"""
        assert INTERRUPT.is_set() is False

    def test_global_set_and_reset(self):
        """글로벌 인스턴스 set/reset 동작"""
        INTERRUPT.set()
        assert INTERRUPT.is_set() is True
        INTERRUPT.reset()
        assert INTERRUPT.is_set() is False


class TestRegisterSignalHandler:
    """register_signal_handler() 테스트"""

    def setup_method(self):
        INTERRUPT.reset()

    def teardown_method(self):
        """시그널 핸들러 복원 (기본값으로)"""
        signal.signal(signal.SIGINT, signal.SIG_DFL)
        signal.signal(signal.SIGTERM, signal.SIG_DFL)
        INTERRUPT.reset()

    def test_register_does_not_raise(self):
        """register_signal_handler() 호출 시 예외 없음"""
        register_signal_handler()  # should not raise

    def test_sigint_sets_interrupt(self):
        """SIGINT 수신 시 INTERRUPT.is_set() == True"""
        register_signal_handler()
        # 현재 프로세스에 SIGINT 직접 전달
        signal.raise_signal(signal.SIGINT)
        assert INTERRUPT.is_set() is True

    def test_sigterm_sets_interrupt(self):
        """SIGTERM 수신 시 INTERRUPT.is_set() == True"""
        register_signal_handler()
        signal.raise_signal(signal.SIGTERM)
        assert INTERRUPT.is_set() is True
