from operator import itemgetter
from typing import TYPE_CHECKING
from zoneinfo import ZoneInfo

import arrow
import bleach
import nh3
from django.conf import settings
from django.utils.timezone import is_naive

if TYPE_CHECKING:
    from .icalevents.icalparser import Event

EVENT_KEYS = ("start", "end", "all_day", "summary", "description", "location", "url")


def split_event_dict_list(event_list: "list[dict]") -> tuple[list[dict], list[dict]]:
    """Splits events and returns list of past events and future events."""
    singularity = arrow.utcnow().shift(hours=-2)

    past = [ev for ev in event_list if ev["end"] < singularity]
    future = list(reversed([ev for ev in event_list if ev["end"] > singularity]))

    return past, future


def set_event_description(event: "Event") -> "Event":
    """Clears even description from unwanted tags."""
    description: str = event.description or ""
    event.description = bleach.clean(description, tags=["a", "br"], strip=True)
    return event


def set_event_duration(event: "Event") -> "Event":
    """Sets duration for event."""
    if event.all_day:
        event.duration = "celĂ˝ den"
        return event

    delta = event.end - event.start
    if delta.days < 1:
        begin = arrow.get(event.start).to(settings.TIME_ZONE).format("H:mm")
        end = arrow.get(event.end).to(settings.TIME_ZONE).format("H:mm")
        event.duration = f"{begin} - {end}"
    else:
        begin = arrow.get(event.start).to(settings.TIME_ZONE).format("H:mm")
        end = arrow.get(event.end).to(settings.TIME_ZONE).format("H:mm (D.M.)")
        event.duration = f"{begin} - {end}"
    return event


def set_event_timezone(event: "Event") -> "Event":
    """Sets default project timezone for event if missing."""
    if is_naive(event.start) or is_naive(event.end):
        event.start = event.start.replace(tzinfo=ZoneInfo(settings.TIME_ZONE))
        event.end = event.end.replace(tzinfo=ZoneInfo(settings.TIME_ZONE))
    return event


def process_event(event: "Event") -> dict:
    """Processes single event for use in Majak"""
    event = set_event_timezone(event)
    event = set_event_duration(event)
    event = set_event_description(event)

    event.description = nh3.clean(
        event.description,
        tags={"h1", "h2", "h3", "h4", "h5", "h6", "a", "em", "p", "b", "strong", "br"},
    )

    # for event in sorted(cal.events, key=attrgetter("start"), reverse=True): TODO check
    return {key: getattr(event, key) for key in EVENT_KEYS}


def process_event_list(event_list: "list[Event]") -> tuple[list[dict], list[dict]]:
    """Parses iCalendar source and returns events as list of dicts. Returns
    tuple of past and future events.
    """
    processed_event_list = list(map(process_event, event_list))
    processed_event_list = sorted(
        processed_event_list, key=itemgetter("start"), reverse=True
    )
    return split_event_dict_list(processed_event_list)