#!/usr/bin/env python
#
# Custom waybar module for clocks. Implemented because the official clock module was downloading timezone definitions on every boot.
import datetime
import json
import sys
import time
from dataclasses import dataclass
from functools import lru_cache
from typing import Final, List, Optional
from zoneinfo import ZoneInfo

INTERVAL: Final[int] = 10
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo


@dataclass
class Update:
    text: Optional[str]
    alt: Optional[str]
    tooltip: Optional[str]
    css_class: Optional[List[str]]
    percentage: Optional[str]

    def dump(self) -> str:
        # Dump a dict because we can't name our member variable "class"
        return json.dumps(
            {
                k: v
                for k, v in {
                    "text": self.text,
                    "alt": self.alt,
                    "tooltip": self.tooltip,
                    "class": self.css_class,
                    "percentage": self.percentage,
                }.items()
                if v is not None
            }
        )


@lru_cache(maxsize=1)
def make_calendar(today: datetime.date, tz: datetime.tzinfo):
    width: Final[int] = 20
    start_of_month = today.replace(day=1)
    month_header = today.strftime("%B %Y")
    padding = width - len(month_header)
    right_padding = " " * (padding // 2)
    left_padding = right_padding + (" " if padding % 2 == 1 else "")
    header = f"{left_padding}{month_header}{right_padding}"
    days_of_week = "Su Mo Tu We Th Fr Sa"

    timezone_str = str(tz)

    # Make the grid
    first_day_padding = " " * (
        0 if start_of_month.weekday() == 6 else (3 * (1 + start_of_month.weekday())) - 1
    )
    output = f"{header}\n{days_of_week}\n{first_day_padding}"

    print_day = start_of_month
    while print_day.month == today.month:
        if print_day.weekday() == 6:
            output += "\n"
        else:
            output += " "
        if print_day == today:
            output += '<span foreground="#323232" background="#CCCCCC">'
        output += f"{print_day.day: >2}"
        if print_day == today:
            output += "</span>"
        print_day += datetime.timedelta(days=1)

    output += f'\n<span size="small">{timezone_str}</span>'
    return output


def main():
    tz: Optional[datetime.tzinfo] = (
        ZoneInfo(sys.argv[1]) if len(sys.argv) >= 2 else LOCAL_TIMEZONE
    )
    if tz is None:
        raise Exception("Failed to detect timezone.")

    next_update = time.time()
    while True:
        time_before_next_update = next_update - time.time()
        if time_before_next_update > 0:
            time.sleep(time_before_next_update)
        next_update = time.time() + INTERVAL

        now = datetime.datetime.now(tz=tz)
        text = now.strftime("%Y-%m-%d %H:%M")
        tooltip = make_calendar(now.date(), tz)

        out = Update(
            text=text,
            alt="foo",
            tooltip=f"<tt>{tooltip}</tt>",
            css_class=["foo"],
            percentage="100",
        )

        print(out.dump(), flush=True)


if __name__ == "__main__":
    main()