# This is free software for the public good of a permacomputer hosted at
# permacomputer.com, an always-on computer by the people, for the people.
# One which is durable, easy to repair, & distributed like tap water
# for machine learning intelligence.
#
# The permacomputer is community-owned infrastructure optimized around
# four values:
#
#   TRUTH      First principles, math & science, open source code freely distributed
#   FREEDOM    Voluntary partnerships, freedom from tyranny & corporate control
#   HARMONY    Minimal waste, self-renewing systems with diverse thriving connections
#   LOVE       Be yourself without hurting others, cooperation through natural law
#
# This software contributes to that vision by archiving the web, preserving digital knowledge before it disappears.
# Code is seeds to sprout on any abandoned technology.

"""
Tests for neopig.logging module.

Tests logging utilities and job log capture.
"""

import pytest
import tempfile
import shutil
import os
import logging
from pathlib import Path
from unittest.mock import patch, MagicMock

from neopig.logging import (
    TqdmLoggingHandler,
    setup_logging,
    start_job_logging,
    stop_job_logging,
    get_job_logs,
    LOGS_PATH,
    JOB_LOG_HANDLERS,
)


class TestTqdmLoggingHandler:
    """Test TqdmLoggingHandler class."""

    @patch('neopig.logging.tqdm')
    def test_emit_writes_through_tqdm(self, mock_tqdm):
        """Test that emit writes through tqdm.write."""
        handler = TqdmLoggingHandler()
        handler.setFormatter(logging.Formatter('%(message)s'))

        record = logging.LogRecord(
            name='test', level=logging.INFO, pathname='', lineno=0,
            msg='Test message', args=(), exc_info=None
        )

        handler.emit(record)
        mock_tqdm.write.assert_called_once_with('Test message')


class TestSetupLogging:
    """Test setup_logging function."""

    def test_configures_root_logger(self):
        """Test that setup_logging configures root logger."""
        setup_logging(level=logging.DEBUG)

        root = logging.getLogger()
        assert root.level == logging.DEBUG
        assert len(root.handlers) >= 1
        assert any(isinstance(h, TqdmLoggingHandler) for h in root.handlers)


class TestJobLogging:
    """Test job-specific logging functions."""

    def setup_method(self):
        self.temp_dir = tempfile.mkdtemp()
        # Patch LOGS_PATH for tests
        import neopig.logging
        self.original_logs_path = neopig.logging.LOGS_PATH
        neopig.logging.LOGS_PATH = Path(self.temp_dir)
        # Clear handlers
        neopig.logging.JOB_LOG_HANDLERS.clear()

    def teardown_method(self):
        # Restore and cleanup
        import neopig.logging
        neopig.logging.LOGS_PATH = self.original_logs_path
        neopig.logging.JOB_LOG_HANDLERS.clear()
        if os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)

    def test_start_job_logging_creates_file(self):
        """Test that start_job_logging creates log file."""
        import neopig.logging
        start_job_logging(123)

        log_file = Path(self.temp_dir) / "123.log"
        assert log_file.exists()
        assert 123 in neopig.logging.JOB_LOG_HANDLERS

        # Cleanup
        stop_job_logging(123)

    def test_stop_job_logging_removes_handler(self):
        """Test that stop_job_logging removes handler."""
        import neopig.logging
        start_job_logging(456)
        assert 456 in neopig.logging.JOB_LOG_HANDLERS

        stop_job_logging(456)
        assert 456 not in neopig.logging.JOB_LOG_HANDLERS

    def test_stop_nonexistent_job(self):
        """Test that stopping non-existent job doesn't raise."""
        stop_job_logging(999)  # Should not raise

    def test_get_job_logs_empty(self):
        """Test getting logs for non-existent job."""
        logs = get_job_logs(999)
        assert logs == ""

    def test_get_job_logs_content(self):
        """Test getting logs content."""
        import neopig.logging
        log_file = Path(self.temp_dir) / "100.log"
        log_file.write_text("Line 1\nLine 2\nLine 3\n")

        logs = get_job_logs(100)
        assert "Line 1" in logs
        assert "Line 2" in logs
        assert "Line 3" in logs

    def test_get_job_logs_tail(self):
        """Test getting last N lines of logs."""
        import neopig.logging
        log_file = Path(self.temp_dir) / "200.log"
        log_file.write_text("Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n")

        logs = get_job_logs(200, tail=2)
        assert "Line 4" in logs
        assert "Line 5" in logs
        assert "Line 1" not in logs


if __name__ == '__main__':
    pytest.main([__file__, '-v'])
