"""Background sync scheduler.

Runs delta sync on a configurable interval using asyncio.
Supports active mode (frequent sync) and idle mode (infrequent).
"""
from __future__ import annotations

import asyncio
import logging
from typing import Any, Callable

from greymatter_core.sync.delta import delta_sync
from greymatter_core.sync.models import SyncResult

logger = logging.getLogger(__name__)


class SyncScheduler:
    """Asyncio-based background sync scheduler.

    Runs delta_sync between local and remote databases on a timer.
    """

    def __init__(
        self,
        local_db: Any,
        remote_db: Any,
        *,
        active_interval: float = 30.0,
        idle_interval: float = 300.0,
        on_sync_complete: Callable[[SyncResult], None] | None = None,
    ):
        self.local_db = local_db
        self.remote_db = remote_db
        self.active_interval = active_interval
        self.idle_interval = idle_interval
        self.on_sync_complete = on_sync_complete

        self._task: asyncio.Task | None = None
        self._running = False
        self._idle = False
        self._last_result: SyncResult | None = None
        self._sync_count = 0

    @property
    def is_running(self) -> bool:
        return self._running

    @property
    def last_result(self) -> SyncResult | None:
        return self._last_result

    @property
    def sync_count(self) -> int:
        return self._sync_count

    @property
    def current_interval(self) -> float:
        return self.idle_interval if self._idle else self.active_interval

    def set_idle(self, idle: bool = True) -> None:
        """Switch between active and idle sync intervals."""
        self._idle = idle

    async def start(self) -> None:
        """Start the background sync loop."""
        if self._running:
            return
        self._running = True
        self._task = asyncio.create_task(self._run_loop())

    async def stop(self) -> None:
        """Stop the background sync loop."""
        self._running = False
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
            self._task = None

    async def sync_now(self) -> SyncResult:
        """Run one sync cycle immediately."""
        return await asyncio.get_event_loop().run_in_executor(
            None, self._do_sync
        )

    async def _run_loop(self) -> None:
        """Internal sync loop."""
        while self._running:
            try:
                await asyncio.sleep(self.current_interval)
                if not self._running:
                    break
                await asyncio.get_event_loop().run_in_executor(
                    None, self._do_sync
                )
            except asyncio.CancelledError:
                break
            except Exception:
                logger.exception("Sync cycle failed")

    def _do_sync(self) -> SyncResult:
        """Execute one sync cycle (runs in thread pool)."""
        result = delta_sync(self.local_db, self.remote_db)
        self._last_result = result
        self._sync_count += 1

        if self.on_sync_complete:
            try:
                self.on_sync_complete(result)
            except Exception:
                logger.exception("on_sync_complete callback failed")

        if not result.success:
            logger.warning("Sync errors: %s", result.errors)

        return result
