"""HTTP-based sync scheduler for cluster mode.

Drop-in replacement for SyncScheduler that uses HTTP sync
instead of direct database-to-database delta_sync.
"""
from __future__ import annotations

import asyncio
import logging
from typing import Any, Callable

from greymatter_core.sync.http_sync import http_delta_sync
from greymatter_core.sync.models import SyncResult

logger = logging.getLogger(__name__)


class HttpSyncScheduler:
    """Sync scheduler that uses HTTP pull/push with the cluster coordinator.

    Compatible with the lifecycle module's bind_sync_to_state_machine().
    """

    def __init__(
        self,
        local_db: Any,
        hub_url: str,
        node_id: str = "solo",
        *,
        active_interval: float = 30.0,
        idle_interval: float = 300.0,
        on_sync_complete: Callable[[SyncResult], None] | None = None,
    ):
        self.local_db = local_db
        self.hub_url = hub_url
        self.node_id = node_id
        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:
        self._idle = idle

    async def start(self) -> None:
        if self._running:
            return
        self._running = True
        self._task = asyncio.create_task(self._run_loop())
        logger.info(
            "HTTP sync scheduler started (hub=%s, interval=%ds)",
            self.hub_url, self.current_interval,
        )

    async def stop(self) -> None:
        self._running = False
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
            self._task = None
        logger.info("HTTP sync scheduler stopped")

    async def sync_now(self) -> SyncResult:
        return await asyncio.get_event_loop().run_in_executor(
            None, self._do_sync
        )

    async def _run_loop(self) -> None:
        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("HTTP sync cycle failed")

    def _do_sync(self) -> SyncResult:
        result = http_delta_sync(
            self.local_db,
            self.hub_url,
            self.node_id,
        )
        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 result.errors:
            logger.warning("HTTP sync errors: %s", result.errors)
        else:
            logger.debug(
                "HTTP sync complete: %d rows, %d tables",
                result.rows_pushed, result.tables_synced,
            )

        return result
