#coachbetter_sync
#!/usr/bin/env python3
"""Coachbetter / St. James Calendar Sync Engine Fetches events via REST API and

outputs a standard .ics feed.
"""

from datetime import datetime, timedelta, timezone
import json
import os
import sys
from urllib.parse import quote_plus
from typing import Optional
from icalendar import Calendar, Event
import requests

# ==============================================================================
# CONFIGURAÇÃO
# ==============================================================================
SEASON_UUID = "e837eb0a-b70e-4a55-a834-3baf7c16a660"
BASE_URL = f"https://register.coachbetter.com/api/v2/seasons/{SEASON_UUID}/events"

# Cole aqui o Bearer token copiado do mitmweb (Request Headers -> Authorization)
# Exemplo: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
BEARER_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIwMTlhNTNlNS02N2ZmLTcwYjQtYjVkYi1jYzI1OTgyY2VkMTIiLCJqdGkiOiJmYjMxYmViMDFiYjViMjM4OWE3NzI5OTZmZDAzOGQyNDkyYzBkMzhmNjA1MWYwYzcwMjhlZmY3MmZiZTY3MmVjZDU2NDIyYTY0OTk3YWZiNCIsImlhdCI6MTc5MDA5MjgxOS43Njg2NzgsIm5iZiI6MTc5MDA5MjgxOS43Njg2OCwiZXhwIjoxNzkwMTc5MjE5Ljc2NzM1Mywic3ViIjoiMTY3NjkyIiwic2NvcGVzIjpbXX0.JvxsysQVqCgIOe3qk2VkLq-jyqQ4RtT4QrfjjgTLS_f3_1DgvJEqBgbVXFyPIezArKPCZOwaK8xoXMXKl6LTnTEmJ8NEufN5wbH5h8hBpGkaxShku5nfcWyN6kPDtgXl7b1MhlOKCjPekTFfTY3k8bDVyC9XZfnCkJN61KO7pMTPaPMtN5_hGmbDx2xMyfMhX2OLPs457zBjdbUSTvWUom_XV9Njo_iWIFjXqMzFfzprejDCi-srK59a_1_GzywBDCchTWgw1rfnPjmWUrALTklfT9SXRBhYg1kIlVmn35FrAo00x3Y5wyaCX1ftCo3-QKfPMf82Z9LWl0CY9i0Fbb5NGM0M41E9d3g4WHYSs7KJUCylamAXMHSybXTMiEM_vh19jEFlFM7jTbUP3m4ruoGENtaaE2FvsuwAfbo54WUMjZj8Em59rfn-jdOgH_m0pspWKGleCFC9SqgamJJw26C21V2Xt5oGSBvllmclUDzEwOQ2gVkPUbeygyjtRuqUlozyIy28Lk7QkTbGKBq4dBE4GlYmFJbxfaHGqmPxNuZb4OzbxlT07dMSCv1S-0yeQV8wJIoGUSf4RgIlwQETy4JIs498BIJ36H4eK5AdA1ZZ_cAKNhr5zVEPwluW5RnfGngaapXz9WN5Xu1tnrEbbfuSUoThcDfyGxFyJHXUyx8"

# Caminho onde o arquivo .ics será gerado
OUTPUT_ICS_PATH = "/home/ubuntu/st_james_schedule.ics"

# Janela de sincronização: últimos 7 dias até os próximos 60 dias
DAYS_PAST = 7
DAYS_FUTURE = 60

HEADERS = {
    "Authorization": f"Bearer {BEARER_TOKEN}",
    "Accept": "application/json",
    "User-Agent": (
        "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15"
    ),
}


def parse_iso_datetime(dt_str: str) -> Optional[datetime]:
  """Converte strings UTC ISO 8601 (terminadas em Z) em objetos datetime cientes de timezone."""
  if not dt_str:
    return None
  clean_str = dt_str.replace("Z", "+00:00")
  return datetime.fromisoformat(clean_str)


def fetch_events() -> list:
  now_utc = datetime.now(timezone.utc)
  overall_start = now_utc - timedelta(days=DAYS_PAST)
  overall_end = now_utc + timedelta(days=DAYS_FUTURE)

  all_events = []
  seen_uuids = set()

  # O limite da API é 35 dias; usamos blocos de 30 dias com segurança
  CHUNK_DAYS = 30
  current_start = overall_start

  print(
      f"[+] Consultando eventos entre {overall_start.strftime('%Y-%m-%d')} e"
      f" {overall_end.strftime('%Y-%m-%d')}..."
  )

  while current_start < overall_end:
    current_end = min(current_start + timedelta(days=CHUNK_DAYS), overall_end)

    start_str = current_start.strftime("%Y-%m-%d 00:00:00")
    end_str = current_end.strftime("%Y-%m-%d 23:59:59")

    params = {"from_datetime": start_str, "to_datetime": end_str}

    print(f"    -> Buscando bloco: {start_str} até {end_str}")
    response = requests.get(
        BASE_URL, headers=HEADERS, params=params, timeout=20
    )

    if response.status_code == 401:
      print(
          "[-] ERRO: Token de autenticação expirado ou inválido (HTTP 401).",
          file=sys.stderr,
      )
      sys.exit(1)
    elif response.status_code != 200:
      print(
          f"[-] Falha na requisição: HTTP {response.status_code} -"
          f" {response.text}",
          file=sys.stderr,
      )
      sys.exit(1)

    payload = response.json()
    chunk_events = payload.get("data", [])

    for item in chunk_events:
      ev = item.get("event", {})
      uuid = ev.get("uuid")
      if uuid and uuid not in seen_uuids:
        seen_uuids.add(uuid)
        all_events.append(item)

    # Avança para o próximo intervalo de dias
    current_start = current_end + timedelta(days=1)

  return all_events

def generate_ics(events_list: list):
  cal = Calendar()
  cal.add("prodid", "-//The St. James FC Coachbetter Sync//EN")
  cal.add("version", "2.0")
  cal.add("x-wr-calname", "St. James FC Soccer")
  cal.add("x-wr-timezone", "UTC")

  total_events = 0

  for item in events_list:
    event_data = item.get("event", {})
    item_type = item.get("type", "event")

    # Identificadores e datas fundamentais
    uuid = event_data.get("uuid")
    start_dt = parse_iso_datetime(event_data.get("start_datetime"))
    end_dt = parse_iso_datetime(event_data.get("end_datetime"))

    if not uuid or not start_dt or not end_dt:
      continue

    cal_event = Event()
    cal_event.add("uid", f"{uuid}@coachbetter")
    cal_event.add("dtstamp", datetime.now(timezone.utc))
    cal_event.add("dtstart", start_dt)
    cal_event.add("dtend", end_dt)

    # Diferenciação entre treinos e partidas oficiais
    if item_type == "match":
      opponent = event_data.get("opponent", "Adversário")
      is_home = event_data.get("home", True)
      venue_type = "Casa" if is_home else "Fora"
      match_type = event_data.get("type", "Jogo").capitalize()

      cal_event.add("summary", f"⚽ Jogo: St. James vs {opponent} ({venue_type})")

      description_parts = [
          f"Tipo: {match_type}",
          f"Adversário: {opponent}",
          f"Mando de campo: {venue_type}",
      ]
      meeting_dt = parse_iso_datetime(event_data.get("meeting_datetime"))
      if meeting_dt:
        description_parts.append(
            f"Horário de Apresentação: {meeting_dt.strftime('%H:%M')} UTC"
        )

      cal_event.add("description", "\n".join(description_parts))

    else:
      focus = event_data.get("focus", "Team Training")
      intensity = event_data.get("intensity", 0)

      cal_event.add("summary", f"🏃 Treino: {focus}")
      cal_event.add(
          "description", f"Atividade: {focus}\nIntensidade: {intensity}"
      )

    location = event_data.get("location")
    if location:
      cal_event.add("location", location)

    cal.add_component(cal_event)
    total_events += 1

  # Gravação do ficheiro no disco
  with open(OUTPUT_ICS_PATH, "wb") as f:
    f.write(cal.to_ical())

  print(
      f"[+] Sucesso: {total_events} eventos exportados para {OUTPUT_ICS_PATH}"
  )


if __name__ == "__main__":
  events = fetch_events()
  generate_ics(events)