"""
Sky EPG Scraper — fetches schedule data from Sky Italia's GTV API.
Also covers Eurosport 1 and Eurosport 2 channels.

Endpoint: https://apid.sky.it/gtv/v1/events
Params: from, to, pageSize, pageNum, env, channels
Returns events with: eventTitle, eventSynopsis, start/end times, image URL
"""
import logging
from datetime import date, datetime, timedelta
from typing import List
from zoneinfo import ZoneInfo

from models import EPGEntry
import config
from scrapers.base_scraper import BaseScraper

logger = logging.getLogger(__name__)

ROME_TZ = ZoneInfo("Europe/Rome")


class SkyScraper(BaseScraper):

    def get_provider_name(self) -> str:
        return "sky"

    def get_channels(self) -> dict:
        return config.SKY_CHANNELS

    def fetch_channel_schedule(self, channel_id: str, channel_name: str,
                                target_date: date) -> List[EPGEntry]:
        # Parse env and channel number from channel_id (format: "DTH#301")
        parts = channel_id.split("#")
        if len(parts) != 2:
            logger.error(f"[sky] Formato channel_id non valido: {channel_id}")
            return []

        env, channel_num = parts
        
        is_timeshift = False
        if channel_name == "Sky Uno Plus":
            channel_num = "9115"
            is_timeshift = True
        elif channel_name == "Sky Collection":
            channel_num = "9047"

        # Target start time (start exactly at midnight to avoid Sky API 422 errors)
        local_start = datetime(
            target_date.year, target_date.month, target_date.day,
            0, 0, 0, tzinfo=ROME_TZ
        )
        
        # Get 28 hours of data to cover the full day plus late-night programs into the next morning
        local_end = local_start + timedelta(hours=28)

        # Convert to UTC for the Sky API query
        utc_start = local_start.astimezone(ZoneInfo("UTC"))
        utc_end = local_end.astimezone(ZoneInfo("UTC"))

        # Sky expects format: YYYY-MM-DDTHH:MM:SSZ
        date_from = utc_start.strftime("%Y-%m-%dT%H:%M:%SZ")
        date_to = utc_end.strftime("%Y-%m-%dT%H:%M:%SZ")

        url = config.SKY_BASE_URL.format(
            date_from=date_from,
            date_to=date_to,
            env=env,
            channel_num=channel_num,
        )

        data = self._make_request(url)
        events = data.get("events", [])
        entries = []

        for event in events:
            try:
                entry = self._parse_event(event, channel_name)
                if entry:
                    if is_timeshift:
                        if entry.start:
                            try:
                                st = datetime.fromisoformat(entry.start)
                                entry.start = (st + timedelta(hours=1)).isoformat()
                            except ValueError:
                                pass
                        if entry.end:
                            try:
                                et = datetime.fromisoformat(entry.end)
                                entry.end = (et + timedelta(hours=1)).isoformat()
                            except ValueError:
                                pass
                    entries.append(entry)
            except Exception as e:
                logger.debug(
                    f"[sky] Errore parsing evento "
                    f"'{event.get('eventTitle', '?')}': {e}"
                )
                continue

        return entries

    def _parse_event(self, event: dict, channel_name: str) -> EPGEntry | None:
        title = event.get("eventTitle", "")
        if not title:
            return None

        # Parse start/end times
        start_str = event.get("starttime", "") or event.get("st", "")
        end_str = event.get("endtime", "") or event.get("et", "")

        start_iso = self._parse_sky_datetime(start_str)
        end_iso = self._parse_sky_datetime(end_str)

        if not start_iso:
            return None

        # Image from imagesMap
        image = ""
        content = event.get("content", {})
        if content:
            images_map = content.get("imagesMap", [])
            if images_map:
                cover_img = None
                for key_to_try in ["scene", "scene_key_art", "background", "cover"]:
                    for img_item in images_map:
                        if img_item.get("key") == key_to_try:
                            cover_img = img_item.get("img", {})
                            break
                    if cover_img:
                        break
                
                if not cover_img and isinstance(images_map, list) and len(images_map) > 0:
                    cover_img = images_map[0].get("img", {})

                if cover_img and cover_img.get("url"):
                    url_path = cover_img["url"]
                    if url_path.startswith("http"):
                        image = url_path
                    else:
                        image = f"https://guidatv.sky.it{url_path}"

        # Fallback 1: eventImage
        if not image:
            event_image = event.get("eventImage", "")
            if event_image:
                if event_image.startswith("http"):
                    image = event_image
                else:
                    image = f"https://guidatv.sky.it{event_image}"

        # Fallback 2: Channel Logo
        if not image:
            ch = event.get("channel", {})
            logo_path = ch.get("logo", "")
            if logo_path:
                if logo_path.startswith("http"):
                    image = logo_path
                else:
                    image = f"https://guidatv.sky.it{logo_path}"

        # Description
        description = (
            event.get("eventSynopsis", "")
            or event.get("eventDescription", "")
            or ""
        ).strip()

        # Category
        category = ""
        genre = event.get("eventGenre", "")
        if genre:
            category = genre
        elif event.get("content", {}).get("genre", {}).get("name"):
            category = event["content"]["genre"]["name"]

        # Season / Episode info — append to title if available
        season = event.get("eventSeason", "")
        episode = event.get("eventEpisode", "")
        subtitle = event.get("eventSubtitle", "")
        if subtitle and subtitle != title:
            title = f"{title} - {subtitle}"

        return EPGEntry(
            title=title,
            image=image,
            channel=channel_name,
            start=start_iso,
            end=end_iso,
            description=description,
            category=category,
        )

    @staticmethod
    def _parse_sky_datetime(dt_str: str) -> str:
        """Parse Sky datetime format to ISO 8601 with Rome timezone."""
        if not dt_str:
            return ""

        try:
            # Sky returns ISO 8601 format, sometimes with Z, sometimes with offset
            if dt_str.endswith("Z"):
                dt = datetime.fromisoformat(dt_str.replace("Z", "+00:00"))
            else:
                dt = datetime.fromisoformat(dt_str)

            # Convert to Rome timezone
            dt_rome = dt.astimezone(ROME_TZ)
            return dt_rome.isoformat()
        except (ValueError, TypeError):
            return ""
