import { initI18n, onLangChange, t, tDyn, getLang } from "./i18n";
import { initSidebar } from "./sidebar";

interface Appointment {
  id: string;
  project_id?: string;
  title: string;
  start_at: string;
  end_at?: string;
  appointment_type?: string;
  project_reference?: string;
  project_title?: string;
}

let allAppointments: Appointment[] = [];
let viewYear = 0;
let viewMonth = 0;

function esc(s: string): string {
  const d = document.createElement("div");
  d.textContent = s;
  return d.innerHTML;
}

function fmtMonth(year: number, month: number): string {
  return `${tDyn(`cal.month.${month}`)} ${year}`;
}

function isoDate(year: number, month: number, day: number): string {
  const m = String(month + 1).padStart(2, "0");
  const d = String(day).padStart(2, "0");
  return `${year}-${m}-${d}`;
}

async function loadAppointments() {
  // Pull a wide window (current month plus a little buffer either side).
  // We could narrow this, but the user typically navigates ±1-2 months
  // and the dataset is small.
  try {
    const resp = await fetch("/api/appointments");
    if (resp.ok) allAppointments = await resp.json();
  } catch {
    /* non-fatal */
  }
}

function appointmentsForDate(iso: string): Appointment[] {
  return allAppointments.filter((t) => t.start_at.slice(0, 10) === iso);
}

function typeClass(t?: string): string {
  return t ? `termin-type-${t}` : "termin-type-default";
}

function fmtTime(iso: string): string {
  try {
    const d = new Date(iso);
    return d.toLocaleTimeString(getLang() === "de" ? "de-DE" : "en-GB", {
      hour: "2-digit",
      minute: "2-digit",
    });
  } catch {
    return iso;
  }
}

function render() {
  document.getElementById("cal-month-label")!.textContent = fmtMonth(viewYear, viewMonth);

  const firstDay = new Date(viewYear, viewMonth, 1);
  const jsWeekday = firstDay.getDay();
  const offset = (jsWeekday + 6) % 7;
  const daysInMonth = new Date(viewYear, viewMonth + 1, 0).getDate();
  const today = new Date();
  const todayISO = isoDate(today.getFullYear(), today.getMonth(), today.getDate());

  const cells: string[] = [];
  for (let i = 0; i < offset; i++) {
    cells.push(`<div class="frist-cal-cell frist-cal-cell-empty"></div>`);
  }
  for (let day = 1; day <= daysInMonth; day++) {
    const iso = isoDate(viewYear, viewMonth, day);
    const items = appointmentsForDate(iso);
    const isToday = iso === todayISO;

    const dots = items
      .slice(0, 4)
      .map((tt) => `<span class="termin-dot ${typeClass(tt.appointment_type)}" title="${esc(tt.title)}"></span>`)
      .join("");
    const more = items.length > 4 ? `<span class="frist-cal-more">+${items.length - 4}</span>` : "";

    cells.push(
      `<div class="frist-cal-cell${isToday ? " frist-cal-today" : ""}${items.length > 0 ? " frist-cal-cell-has" : ""}" data-iso="${iso}">
        <span class="frist-cal-day">${day}</span>
        <div class="frist-cal-dots">${dots}${more}</div>
      </div>`,
    );
  }

  const grid = document.getElementById("appointment-cal-grid")!;
  grid.innerHTML = cells.join("");

  grid.querySelectorAll<HTMLElement>(".frist-cal-cell-has").forEach((cell) => {
    cell.addEventListener("click", () => openPopup(cell.dataset.iso!));
  });

  const monthStart = isoDate(viewYear, viewMonth, 1);
  const monthEnd = isoDate(viewYear, viewMonth, daysInMonth);
  const hasInMonth = allAppointments.some((tt) => {
    const iso = tt.start_at.slice(0, 10);
    return iso >= monthStart && iso <= monthEnd;
  });
  const empty = document.getElementById("appointment-cal-empty")!;
  empty.style.display = hasInMonth ? "none" : "";
}

function openPopup(iso: string) {
  const items = appointmentsForDate(iso);
  if (items.length === 0) return;
  const popup = document.getElementById("cal-popup")!;
  const dateEl = document.getElementById("cal-popup-date")!;
  const list = document.getElementById("cal-popup-list")!;

  const d = new Date(iso + "T00:00:00");
  dateEl.textContent = d.toLocaleDateString(getLang() === "de" ? "de-DE" : "en-GB", {
    weekday: "long",
    year: "numeric",
    month: "long",
    day: "numeric",
  });

  list.innerHTML = items
    .map((tt) => {
      const akteRef = tt.project_id
        ? `<a href="/projects/${esc(tt.project_id)}" class="frist-cal-popup-project">${esc(tt.project_reference ?? "")}</a>`
        : `<span class="termin-personal-tag">${esc(t("appointments.personal"))}</span>`;
      return `<li class="frist-cal-popup-item">
        <span class="termin-dot ${typeClass(tt.appointment_type)}"></span>
        <span class="frist-cal-popup-time">${esc(fmtTime(tt.start_at))}</span>
        <a href="/appointments/${esc(tt.id)}" class="frist-cal-popup-title">${esc(tt.title)}</a>
        ${akteRef}
      </li>`;
    })
    .join("");
  popup.style.display = "flex";
}

function initPopup() {
  const popup = document.getElementById("cal-popup")!;
  const close = document.getElementById("cal-popup-close")!;
  close.addEventListener("click", () => (popup.style.display = "none"));
  popup.addEventListener("click", (e) => {
    if (e.target === e.currentTarget) popup.style.display = "none";
  });
}

function initNav() {
  document.getElementById("cal-prev")!.addEventListener("click", () => {
    viewMonth -= 1;
    if (viewMonth < 0) {
      viewMonth = 11;
      viewYear -= 1;
    }
    render();
  });
  document.getElementById("cal-next")!.addEventListener("click", () => {
    viewMonth += 1;
    if (viewMonth > 11) {
      viewMonth = 0;
      viewYear += 1;
    }
    render();
  });
  document.getElementById("cal-today")!.addEventListener("click", () => {
    const now = new Date();
    viewYear = now.getFullYear();
    viewMonth = now.getMonth();
    render();
  });
}

document.addEventListener("DOMContentLoaded", async () => {
  initI18n();
  initSidebar();
  const now = new Date();
  viewYear = now.getFullYear();
  viewMonth = now.getMonth();
  initNav();
  initPopup();
  onLangChange(render);
  await loadAppointments();
  render();
});
