import {
  MONTHS,
  DAY_INDEX_TO_DAY,
  DAY_TO_GERMAN,
  DAY_TO_GERMAN_SHORT,
  MONTH_TO_GERMAN,
  ExpandedEvent,
} from "@calchat/shared";
import { EventService } from "../services/EventService";
import { expandRecurringEvents } from "./recurrenceExpander";

// Private formatting helpers

function formatTime(date: Date): string {
  const hours = date.getHours().toString().padStart(2, "0");
  const minutes = date.getMinutes().toString().padStart(2, "0");
  return `${hours}:${minutes}`;
}

function formatDateShort(date: Date): string {
  const day = date.getDate().toString().padStart(2, "0");
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
  return `${day}.${month}.`;
}

function getWeekNumber(date: Date): number {
  const d = new Date(
    Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),
  );
  const dayNum = d.getUTCDay() || 7;
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}

function formatWeeksText(events: ExpandedEvent[], weeks: number): string {
  const weeksText =
    weeks === 1 ? "die nächste Woche" : `die nächsten ${weeks} Wochen`;

  if (events.length === 0) {
    return `Du hast für ${weeksText} keine Termine.`;
  }

  const lines: string[] = [`Hier sind deine Termine für ${weeksText}:\n`];

  for (const event of events) {
    const day = DAY_INDEX_TO_DAY[event.occurrenceStart.getDay()];
    const weekday = DAY_TO_GERMAN[day];
    const dateStr = formatDateShort(event.occurrenceStart);
    const timeStr = formatTime(event.occurrenceStart);
    lines.push(`${weekday}, ${dateStr} - ${timeStr} Uhr: ${event.title}`);
  }

  lines.push(
    `\nInsgesamt ${events.length} Termin${events.length === 1 ? "" : "e"}.`,
  );
  return lines.join("\n");
}

function formatMonthText(events: ExpandedEvent[], monthName: string): string {
  if (events.length === 0) {
    return `Du hast im ${monthName} keine Termine.`;
  }

  // Group events by calendar week
  const weekGroups = new Map<number, ExpandedEvent[]>();
  for (const event of events) {
    const weekNum = getWeekNumber(event.occurrenceStart);
    if (!weekGroups.has(weekNum)) {
      weekGroups.set(weekNum, []);
    }
    weekGroups.get(weekNum)!.push(event);
  }

  const lines: string[] = [
    `Hier ist deine Monatsübersicht für ${monthName}:\n`,
  ];

  // Sort weeks and format
  const sortedWeeks = Array.from(weekGroups.keys()).sort((a, b) => a - b);
  for (const weekNum of sortedWeeks) {
    const weekEvents = weekGroups.get(weekNum)!;
    lines.push(
      `KW ${weekNum}: ${weekEvents.length} Termin${weekEvents.length === 1 ? "" : "e"}`,
    );

    for (const event of weekEvents) {
      const day = DAY_INDEX_TO_DAY[event.occurrenceStart.getDay()];
      const weekdayShort = DAY_TO_GERMAN_SHORT[day];
      const dateStr = formatDateShort(event.occurrenceStart);
      const timeStr = formatTime(event.occurrenceStart);
      lines.push(`  • ${weekdayShort} ${dateStr}, ${timeStr}: ${event.title}`);
    }
    lines.push("");
  }

  lines.push(
    `Insgesamt ${events.length} Termin${events.length === 1 ? "" : "e"} im ${monthName}.`,
  );
  return lines.join("\n");
}

// Public API

/**
 * Get a formatted overview of events for the next x weeks.
 * Recurring events are expanded to show all occurrences within the range.
 */
export async function getWeeksOverview(
  eventService: EventService,
  userId: string,
  weeks: number,
): Promise<string> {
  const now = new Date();
  const endDate = new Date(now.getTime() + weeks * 7 * 24 * 60 * 60 * 1000);
  const events = await eventService.getAll(userId);
  const expanded = expandRecurringEvents(events, now, endDate);
  return formatWeeksText(expanded, weeks);
}

/**
 * Get a formatted overview of events for a specific month.
 * Recurring events are expanded to show all occurrences within the month.
 */
export async function getMonthOverview(
  eventService: EventService,
  userId: string,
  year: number,
  month: number,
): Promise<string> {
  const startOfMonth = new Date(year, month, 1);
  const endOfMonth = new Date(year, month + 1, 0, 23, 59, 59);
  const events = await eventService.getAll(userId);
  const expanded = expandRecurringEvents(events, startOfMonth, endOfMonth);
  const monthName = MONTH_TO_GERMAN[MONTHS[month]];
  return formatMonthText(expanded, monthName);
}
