"""Scheduler service provider — virtual provider that emits events on a schedule."""

from __future__ import annotations

import logging
from datetime import datetime, timezone
from typing import Any
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError

from notify_bridge_core.models.events import EventType, ServiceEvent
from notify_bridge_core.providers.base import ServiceProvider, ServiceProviderType
from notify_bridge_core.templates.variables import TemplateVariableDefinition

_LOGGER = logging.getLogger(__name__)

_WEEKDAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

SCHEDULER_VARIABLES: list[TemplateVariableDefinition] = [
    TemplateVariableDefinition(
        name="schedule_name",
        type="string",
        description="Name of the scheduled tracker",
        example="Daily standup reminder",
        provider_type=ServiceProviderType.SCHEDULER,
    ),
    TemplateVariableDefinition(
        name="fire_count",
        type="int",
        description="How many times this schedule has fired",
        example="42",
        provider_type=ServiceProviderType.SCHEDULER,
    ),
    TemplateVariableDefinition(
        name="current_date",
        type="string",
        description="Current date (formatted)",
        example="22.03.2026",
        provider_type=ServiceProviderType.SCHEDULER,
    ),
    TemplateVariableDefinition(
        name="current_time",
        type="string",
        description="Current time (formatted)",
        example="09:00",
        provider_type=ServiceProviderType.SCHEDULER,
    ),
    TemplateVariableDefinition(
        name="current_datetime",
        type="string",
        description="Current date and time (formatted)",
        example="22.03.2026, 09:00 UTC",
        provider_type=ServiceProviderType.SCHEDULER,
    ),
    TemplateVariableDefinition(
        name="weekday",
        type="string",
        description="Day of the week",
        example="Monday",
        provider_type=ServiceProviderType.SCHEDULER,
    ),
    TemplateVariableDefinition(
        name="timezone",
        type="string",
        description="IANA timezone used to compute current_date/time",
        example="Europe/Warsaw",
        provider_type=ServiceProviderType.SCHEDULER,
    ),
    TemplateVariableDefinition(
        name="custom_vars",
        type="dict",
        description="User-defined key-value pairs (also available as top-level variables)",
        example='{"team": "Engineering", "channel": "#general"}',
        provider_type=ServiceProviderType.SCHEDULER,
    ),
]


class SchedulerServiceProvider(ServiceProvider):
    """Virtual provider that generates events on a schedule.

    No external service connection. The poll() method creates a
    SCHEDULED_MESSAGE event with datetime info and custom variables.
    """

    provider_type = ServiceProviderType.SCHEDULER

    def __init__(
        self,
        name: str = "Scheduler",
        tracker_name: str = "",
        custom_variables: dict[str, str] | None = None,
        date_format: str = "%d.%m.%Y",
        time_format: str = "%H:%M",
        datetime_format: str = "%d.%m.%Y, %H:%M %Z",
        timezone_name: str | None = None,
    ) -> None:
        self._name = name
        self._tracker_name = tracker_name
        self._custom_variables = custom_variables or {}
        self._date_format = date_format
        self._time_format = time_format
        self._datetime_format = datetime_format
        # Resolve a timezone for date/time rendering. Falls back to UTC on
        # invalid IANA names so a typo in app settings doesn't break polls.
        tz: ZoneInfo
        if timezone_name:
            try:
                tz = ZoneInfo(timezone_name)
            except (ZoneInfoNotFoundError, ValueError):
                _LOGGER.warning("Unknown timezone %r; falling back to UTC", timezone_name)
                tz = ZoneInfo("UTC")
        else:
            tz = ZoneInfo("UTC")
        self._tz = tz

    async def connect(self) -> bool:
        return True  # virtual provider — always connected

    async def disconnect(self) -> None:
        pass

    async def poll(
        self,
        collection_ids: list[str],
        tracker_state: dict[str, Any],
    ) -> tuple[list[ServiceEvent], dict[str, Any]]:
        now_utc = datetime.now(timezone.utc)
        now = now_utc.astimezone(self._tz)
        # State uses {collection_id: {dict}} convention like other providers
        sched_state = tracker_state.get("scheduler", {})
        fire_count = sched_state.get("fire_count", 0) + 1

        extra: dict[str, Any] = {
            "schedule_name": self._tracker_name,
            "fire_count": fire_count,
            "current_date": now.strftime(self._date_format),
            "current_time": now.strftime(self._time_format),
            "current_datetime": now.strftime(self._datetime_format),
            "weekday": _WEEKDAYS[now.weekday()],
            "timezone": self._tz.key,
            "custom_vars": dict(self._custom_variables),
        }
        # Flatten custom variables at top level for easy template access
        extra.update(self._custom_variables)

        event = ServiceEvent(
            event_type=EventType.SCHEDULED_MESSAGE,
            provider_type=ServiceProviderType.SCHEDULER,
            provider_name=self._name,
            collection_id="scheduler",
            collection_name=self._tracker_name,
            timestamp=now,
            extra=extra,
        )

        new_state = {
            "scheduler": {
                "name": self._tracker_name,
                "fire_count": fire_count,
                "asset_ids": [],
                "pending_asset_ids": [],
            },
        }
        return [event], new_state

    def get_available_variables(self) -> list[TemplateVariableDefinition]:
        return list(SCHEDULER_VARIABLES)

    def get_provider_config_schema(self) -> dict[str, Any]:
        return {
            "type": "object",
            "properties": {},
            "required": [],
        }

    async def list_collections(self) -> list[dict[str, Any]]:
        return []  # no collections concept

    async def test_connection(self) -> dict[str, Any]:
        return {"ok": True, "message": "Virtual provider — always available"}
