"""
SQS visibility timeout heartbeat manager.

Single Responsibility: Extend SQS message visibility for long-running jobs.
"""

import threading
import time
from typing import Optional

from ..clients.sqs_client import SQSClient


class VisibilityHeartbeat:
    """
    Background thread that extends SQS visibility timeout.

    Prevents long-running jobs from timing out and being
    picked up by other workers.
    """

    def __init__(
        self,
        sqs_client: SQSClient,
        receipt_handle: str,
        heartbeat_interval: int = 240,
        visibility_timeout: int = 300,
    ):
        """
        Initialize heartbeat manager.

        Args:
            sqs_client: SQS client for visibility operations
            receipt_handle: SQS message receipt handle
            heartbeat_interval: Seconds between heartbeats (default 4 min)
            visibility_timeout: Timeout to set on each heartbeat (default 5 min)
        """
        self.sqs_client = sqs_client
        self.receipt_handle = receipt_handle
        self.heartbeat_interval = heartbeat_interval
        self.visibility_timeout = visibility_timeout
        self._stop_event = threading.Event()
        self._thread: Optional[threading.Thread] = None

    def start(self) -> None:
        """
        Start heartbeat thread.

        Thread extends visibility every heartbeat_interval seconds.
        """
        if self._thread and self._thread.is_alive():
            print("WARNING: Heartbeat already running")
            return

        print(
            f"Starting SQS visibility heartbeat (interval={self.heartbeat_interval}s, "
            f"timeout={self.visibility_timeout}s)"
        )

        self._stop_event.clear()
        self._thread = threading.Thread(target=self._run, daemon=True)
        self._thread.start()

    def stop(self) -> None:
        """
        Stop heartbeat thread.

        Waits for thread to finish gracefully.
        """
        if not self._thread or not self._thread.is_alive():
            return

        print("Stopping SQS visibility heartbeat")
        self._stop_event.set()
        self._thread.join(timeout=5)

    def _run(self) -> None:
        """
        Heartbeat thread main loop.

        Extends visibility timeout every heartbeat_interval seconds
        until stopped.
        """
        while not self._stop_event.is_set():
            # Wait for heartbeat interval (interruptible)
            if self._stop_event.wait(timeout=self.heartbeat_interval):
                break

            # Extend visibility
            try:
                self.sqs_client.change_visibility_timeout(
                    self.receipt_handle, self.visibility_timeout
                )
                print(
                    f"Extended SQS visibility timeout to {self.visibility_timeout}s"
                )
            except Exception as e:
                print(f"ERROR: Failed to extend SQS visibility: {e}")
                # Continue heartbeat - transient errors shouldn't stop it
