# GstMini
# Copyright (C) 2025 Rafael Caricio <rafael@caricio.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.

"""GstClock - Timing and synchronization."""

import time
from typing import Tuple


class GstClockReturn:
    """Return values from clock operations."""
    OK = "ok"
    EARLY = "early"
    UNSCHEDULED = "unscheduled"
    BADTIME = "badtime"


class GstClock:
    """
    Simplified GstClock for timing and synchronization.

    Corresponds to gst_clock_id_wait in gstbasesink.c:2381
    """

    def __init__(self):
        """Create a clock."""
        self._start_time = None

    def start(self):
        """Start the clock (called when pipeline goes to PLAYING)."""
        self._start_time = time.monotonic()

    def get_time(self) -> float:
        """
        Get current clock time in seconds.

        Returns:
            Time in seconds since clock started, or 0 if not started
        """
        if self._start_time is None:
            return 0.0
        return time.monotonic() - self._start_time

    def wait_until(self, target_time: float) -> Tuple[str, float]:
        """
        Wait until the clock reaches the target time.

        This is similar to gst_clock_id_wait in gstbasesink.c:2381

        Args:
            target_time: Target time to wait for (in seconds)

        Returns:
            Tuple of (GstClockReturn, jitter in seconds)
            - jitter > 0: woke up late
            - jitter < 0: woke up early
            - jitter = 0: perfect timing
        """
        if self._start_time is None:
            return (GstClockReturn.BADTIME, 0.0)

        current = self.get_time()
        wait_duration = target_time - current

        if wait_duration <= 0:
            # Already past target time - return immediately with negative jitter
            jitter = -wait_duration
            return (GstClockReturn.OK, jitter)

        # Sleep until target time
        time.sleep(wait_duration)

        # Calculate jitter (how far off we were)
        actual_time = self.get_time()
        jitter = actual_time - target_time

        return (GstClockReturn.OK, jitter)

    def __repr__(self) -> str:
        if self._start_time is None:
            return "GstClock(stopped)"
        return f"GstClock(time={self.get_time():.3f}s)"
