// スペース／横断カレンダー共通のピュア関数。
// 月グリッドの組み立て・期間/時刻の整形・複数日イベントの横棒レイアウトを
// 1 か所に集約し、SpaceCalendar と CrossSpaceCalendar の「見え方」を揃える。
import type { CalendarEvent } from '../api';
import { localToday, shiftDay } from './localDate';

export const WEEKDAYS = ['日', '月', '火', '水', '木', '金', '土'] as const;

/** 'YYYY-MM' of the viewer's local today. */
export function localMonth(): string {
  return localToday().slice(0, 7);
}

/** month ± delta, as 'YYYY-MM'（1 日基準で UTC 暦演算）。 */
export function shiftMonth(month: string, delta: number): string {
  const [y, m] = month.split('-').map(Number);
  const d = new Date(Date.UTC(y, m - 1 + delta, 1));
  return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;
}

/** 月グリッドの全 'YYYY-MM-DD' セル（日曜始まり・6 週固定）。 */
export function monthGridDays(month: string): string[] {
  const [y, m] = month.split('-').map(Number);
  const first = new Date(Date.UTC(y, m - 1, 1));
  const start = shiftDay(first.toISOString().slice(0, 10), -first.getUTCDay());
  const days: string[] = [];
  // 6 週あればどの月レイアウトも収まる（最大 31 日 + 先頭 6 日）。
  for (let i = 0; i < 42; i++) days.push(shiftDay(start, i));
  return days;
}

/** 月グリッドの日配列を 7 日ごとの週に分割する。 */
export function splitWeeks(days: string[]): string[][] {
  const out: string[][] = [];
  for (let i = 0; i < days.length; i += 7) out.push(days.slice(i, i + 7));
  return out;
}

/** 'YYYY-MM-DD' → 'M/D'。 */
export function fmtMonthDay(d: string): string {
  return `${Number(d.slice(5, 7))}/${Number(d.slice(8, 10))}`;
}

/** 予定の期間を短く: 単日は 'M/D'、複数日は 'M/D–M/D'。 */
export function fmtRange(ev: Pick<CalendarEvent, 'date' | 'endDate'>): string {
  const end = ev.endDate && ev.endDate > ev.date ? ev.endDate : null;
  return end ? `${fmtMonthDay(ev.date)}–${fmtMonthDay(end)}` : fmtMonthDay(ev.date);
}

/** 時刻バッジ表示: 終日 / '09:00' / '09:00–10:30'。 */
export function fmtTimeBadge(ev: Pick<CalendarEvent, 'time' | 'endTime'>): string {
  if (!ev.time) return '終日';
  return ev.endTime ? `${ev.time}–${ev.endTime}` : ev.time;
}

/** 1 週（7 日）にかかるイベントを、横棒の lane（重ならない行）に割り付ける。 */
export interface WeekBar {
  ev: CalendarEvent;
  colStart: number;   // 1–7
  colSpan: number;
  lane: number;       // 0-based の積み上げ行
  continuesLeft: boolean;
  continuesRight: boolean;
}

export function layoutWeekBars(weekDays: string[], events: CalendarEvent[]): WeekBar[] {
  const weekStart = weekDays[0]!;
  const weekEnd = weekDays[6]!;
  const segs = events
    .map((ev) => {
      const evEnd = ev.endDate && ev.endDate > ev.date ? ev.endDate : ev.date;
      if (evEnd < weekStart || ev.date > weekEnd) return null;
      const segStart = ev.date < weekStart ? weekStart : ev.date;
      const segEnd = evEnd > weekEnd ? weekEnd : evEnd;
      const colStart = weekDays.indexOf(segStart) + 1;
      const colEnd = weekDays.indexOf(segEnd) + 1;
      return {
        ev,
        colStart,
        colSpan: colEnd - colStart + 1,
        continuesLeft: ev.date < weekStart,
        continuesRight: evEnd > weekEnd,
      };
    })
    .filter((s): s is Omit<WeekBar, 'lane'> => s !== null)
    // 長い棒・早い開始を優先して上の lane に積む
    .sort((a, b) => b.colSpan - a.colSpan || a.colStart - b.colStart || a.ev.id - b.ev.id);

  const laneEnds: number[] = []; // lane ごとの「最後に埋まった列」
  const bars: WeekBar[] = [];
  for (const s of segs) {
    let lane = laneEnds.findIndex((end) => end < s.colStart);
    if (lane === -1) { lane = laneEnds.length; laneEnds.push(0); }
    laneEnds[lane] = s.colStart + s.colSpan - 1;
    bars.push({ ...s, lane });
  }
  return bars;
}
