from unittest.mock import Mock, patch
from bouquin.pomodoro_timer import PomodoroTimer, PomodoroManager


def test_pomodoro_timer_init(qtbot, app, fresh_db):
    """Test PomodoroTimer initialization."""
    task_text = "Write unit tests"
    timer = PomodoroTimer(task_text)
    qtbot.addWidget(timer)

    assert timer._task_text == task_text
    assert timer._elapsed_seconds == 0
    assert timer._running is False
    assert timer.time_label.text() == "00:00:00"
    assert timer.stop_btn.isEnabled() is False


def test_pomodoro_timer_start(qtbot, app):
    """Test starting the timer."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    timer._toggle_timer()

    assert timer._running is True
    assert timer.stop_btn.isEnabled() is True


def test_pomodoro_timer_pause(qtbot, app):
    """Test pausing the timer."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    # Start the timer
    timer._toggle_timer()
    assert timer._running is True

    # Pause the timer
    timer._toggle_timer()
    assert timer._running is False


def test_pomodoro_timer_resume(qtbot, app):
    """Test resuming the timer after pause."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    # Start, pause, then resume
    timer._toggle_timer()  # Start
    timer._toggle_timer()  # Pause
    timer._toggle_timer()  # Resume

    assert timer._running is True


def test_pomodoro_timer_tick(qtbot, app):
    """Test timer tick increments elapsed time."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    initial_time = timer._elapsed_seconds
    timer._tick()

    assert timer._elapsed_seconds == initial_time + 1


def test_pomodoro_timer_display_update(qtbot, app):
    """Test display updates with various elapsed times."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    # Test 0 seconds
    timer._elapsed_seconds = 0
    timer._update_display()
    assert timer.time_label.text() == "00:00:00"

    # Test 65 seconds (1 min 5 sec)
    timer._elapsed_seconds = 65
    timer._update_display()
    assert timer.time_label.text() == "00:01:05"

    # Test 3665 seconds (1 hour 1 min 5 sec)
    timer._elapsed_seconds = 3665
    timer._update_display()
    assert timer.time_label.text() == "01:01:05"

    # Test 3600 seconds (1 hour exactly)
    timer._elapsed_seconds = 3600
    timer._update_display()
    assert timer.time_label.text() == "01:00:00"


def test_pomodoro_timer_stop_and_log_running(qtbot, app):
    """Test stopping the timer while it's running."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    # Start the timer
    timer._toggle_timer()
    timer._elapsed_seconds = 100

    # Connect a mock to the signal
    signal_received = []
    timer.timerStopped.connect(lambda s, t: signal_received.append((s, t)))

    timer._stop_and_log()

    assert timer._running is False
    assert len(signal_received) == 1
    assert signal_received[0][0] == 100  # elapsed seconds
    assert signal_received[0][1] == "Test task"


def test_pomodoro_timer_stop_and_log_paused(qtbot, app):
    """Test stopping the timer when it's paused."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    timer._elapsed_seconds = 50

    signal_received = []
    timer.timerStopped.connect(lambda s, t: signal_received.append((s, t)))

    timer._stop_and_log()

    assert len(signal_received) == 1
    assert signal_received[0][0] == 50


def test_pomodoro_timer_multiple_ticks(qtbot, app):
    """Test multiple timer ticks."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    for i in range(10):
        timer._tick()

    assert timer._elapsed_seconds == 10
    assert "00:00:10" in timer.time_label.text()


def test_pomodoro_timer_modal_state(qtbot, app):
    """Test that timer is non-modal."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    assert timer.isModal() is False


def test_pomodoro_timer_window_title(qtbot, app):
    """Test timer window title."""
    timer = PomodoroTimer("Test task")
    qtbot.addWidget(timer)

    # Window title should contain some reference to timer/pomodoro
    assert len(timer.windowTitle()) > 0


def test_pomodoro_manager_init(app, fresh_db):
    """Test PomodoroManager initialization."""
    parent = Mock()
    manager = PomodoroManager(fresh_db, parent)

    assert manager._db is fresh_db
    assert manager._parent is parent
    assert manager._active_timer is None


def test_pomodoro_manager_start_timer(qtbot, app, fresh_db):
    """Test starting a timer through the manager."""
    from PySide6.QtWidgets import QWidget

    parent = QWidget()
    qtbot.addWidget(parent)
    manager = PomodoroManager(fresh_db, parent)

    line_text = "Important task"
    date_iso = "2024-01-15"

    manager.start_timer_for_line(line_text, date_iso)

    assert manager._active_timer is not None
    assert manager._active_timer._task_text == line_text
    qtbot.addWidget(manager._active_timer)


def test_pomodoro_manager_replace_active_timer(qtbot, app, fresh_db):
    """Test that starting a new timer closes the previous one."""
    from PySide6.QtWidgets import QWidget

    parent = QWidget()
    qtbot.addWidget(parent)
    manager = PomodoroManager(fresh_db, parent)

    # Start first timer
    manager.start_timer_for_line("Task 1", "2024-01-15")
    first_timer = manager._active_timer
    qtbot.addWidget(first_timer)
    first_timer.show()

    # Start second timer
    manager.start_timer_for_line("Task 2", "2024-01-16")
    second_timer = manager._active_timer
    qtbot.addWidget(second_timer)

    assert first_timer is not second_timer
    assert second_timer._task_text == "Task 2"


def test_pomodoro_manager_on_timer_stopped_minimum_hours(
    qtbot, app, fresh_db, monkeypatch
):
    """Test that timer stopped with very short time logs minimum hours."""
    parent = Mock()
    manager = PomodoroManager(fresh_db, parent)

    # Mock TimeLogDialog to avoid actually showing it
    mock_dialog = Mock()
    mock_dialog.hours_spin = Mock()
    mock_dialog.note = Mock()
    mock_dialog.exec = Mock()

    with patch("bouquin.pomodoro_timer.TimeLogDialog", return_value=mock_dialog):
        manager._on_timer_stopped(10, "Quick task", "2024-01-15")

        # Should set minimum of 0.25 hours
        mock_dialog.hours_spin.setValue.assert_called_once()
        hours_set = mock_dialog.hours_spin.setValue.call_args[0][0]
        assert hours_set >= 0.25


def test_pomodoro_manager_on_timer_stopped_rounding(qtbot, app, fresh_db, monkeypatch):
    """Test that elapsed time is properly rounded to decimal hours."""
    parent = Mock()
    manager = PomodoroManager(fresh_db, parent)

    mock_dialog = Mock()
    mock_dialog.hours_spin = Mock()
    mock_dialog.note = Mock()
    mock_dialog.exec = Mock()

    with patch("bouquin.pomodoro_timer.TimeLogDialog", return_value=mock_dialog):
        # Test with 1800 seconds (30 minutes)
        manager._on_timer_stopped(1800, "Task", "2024-01-15")

        mock_dialog.hours_spin.setValue.assert_called_once()
        hours_set = mock_dialog.hours_spin.setValue.call_args[0][0]
        # Should round up and be a multiple of 0.25
        assert hours_set > 0
        assert hours_set * 4 == int(hours_set * 4)  # Multiple of 0.25


def test_pomodoro_manager_on_timer_stopped_prefills_note(
    qtbot, app, fresh_db, monkeypatch
):
    """Test that timer stopped pre-fills the note in time log dialog."""
    parent = Mock()
    manager = PomodoroManager(fresh_db, parent)

    mock_dialog = Mock()
    mock_dialog.hours_spin = Mock()
    mock_dialog.note = Mock()
    mock_dialog.exec = Mock()

    task_text = "Write documentation"

    with patch("bouquin.pomodoro_timer.TimeLogDialog", return_value=mock_dialog):
        manager._on_timer_stopped(3600, task_text, "2024-01-15")

        mock_dialog.note.setText.assert_called_once_with(task_text)


def test_pomodoro_manager_timer_stopped_signal_connection(
    qtbot, app, fresh_db, monkeypatch
):
    """Test that timer stopped signal is properly connected."""
    from PySide6.QtWidgets import QWidget

    parent = QWidget()
    qtbot.addWidget(parent)
    manager = PomodoroManager(fresh_db, parent)

    # Mock TimeLogDialog
    mock_dialog = Mock()
    mock_dialog.hours_spin = Mock()
    mock_dialog.note = Mock()
    mock_dialog.exec = Mock()

    with patch("bouquin.pomodoro_timer.TimeLogDialog", return_value=mock_dialog):
        manager.start_timer_for_line("Task", "2024-01-15")
        timer = manager._active_timer
        qtbot.addWidget(timer)

        # Simulate timer stopped
        timer._elapsed_seconds = 1000
        timer._stop_and_log()

        # TimeLogDialog should have been created
        assert mock_dialog.exec.called


def test_pomodoro_timer_accepts_parent(qtbot, app):
    """Test that timer accepts a parent widget."""
    from PySide6.QtWidgets import QWidget

    parent = QWidget()
    qtbot.addWidget(parent)
    timer = PomodoroTimer("Task", parent)
    qtbot.addWidget(timer)

    assert timer.parent() is parent


def test_pomodoro_manager_no_active_timer_initially(app, fresh_db):
    """Test that manager starts with no active timer."""
    parent = Mock()
    manager = PomodoroManager(fresh_db, parent)

    assert manager._active_timer is None


def test_pomodoro_timer_start_stop_cycle(qtbot, app):
    """Test a complete start-stop cycle."""
    timer = PomodoroTimer("Complete cycle")
    qtbot.addWidget(timer)

    signal_received = []
    timer.timerStopped.connect(lambda s, t: signal_received.append((s, t)))

    # Start
    timer._toggle_timer()
    assert timer._running is True

    # Simulate some ticks
    for _ in range(5):
        timer._tick()

    # Stop
    timer._stop_and_log()
    assert timer._running is False
    assert len(signal_received) == 1
    assert signal_received[0][0] == 5


def test_pomodoro_timer_long_elapsed_time(qtbot, app):
    """Test display with very long elapsed time."""
    timer = PomodoroTimer("Long task")
    qtbot.addWidget(timer)

    # Set to 2 hours, 34 minutes, 56 seconds
    timer._elapsed_seconds = 2 * 3600 + 34 * 60 + 56
    timer._update_display()

    assert timer.time_label.text() == "02:34:56"
