import type { Dayjs } from 'dayjs';
import type { PersonalCalendarItem } from '@/types/api';

export type CalendarViewMode = 'day' | '3day' | 'week' | 'month';

export const START_HOUR = 6;
export const END_HOUR = 22;
export const SLOT_HEIGHT = 60; // px per hour

/** Convert a hex color to rgba string */
export function hexToRgba(hex: string, alpha: number): string {
  const cleaned = hex.replace('#', '');
  if (cleaned.length !== 6) return `rgba(24, 144, 255, ${alpha})`;
  const r = parseInt(cleaned.slice(0, 2), 16);
  const g = parseInt(cleaned.slice(2, 4), 16);
  const b = parseInt(cleaned.slice(4, 6), 16);
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}

/** Calculate pixel position and height for a timed calendar item */
export function positionTimedItem(item: PersonalCalendarItem): { top: number; height: number } {
  const parts = item.startTime.split(':');
  const sh = parseInt(parts[0] ?? '0', 10);
  const sm = parseInt(parts[1] ?? '0', 10);
  const endParts = item.endTime.split(':');
  const eh = parseInt(endParts[0] ?? '0', 10);
  const em = parseInt(endParts[1] ?? '0', 10);
  const startMinutes = sh * 60 + sm;
  const endMinutes = eh * 60 + em;
  const topMinutes = startMinutes - START_HOUR * 60;
  const durationMinutes = Math.max(endMinutes - startMinutes, 15);

  return {
    top: Math.max(0, (topMinutes / 60) * SLOT_HEIGHT),
    height: Math.max(20, (durationMinutes / 60) * SLOT_HEIGHT),
  };
}

export interface LanedItem {
  item: PersonalCalendarItem;
  top: number;
  height: number;
  lane: number;
  totalLanes: number;
}

/** Assign lanes for overlapping timed items so they render side-by-side */
export function assignLanes(items: PersonalCalendarItem[]): LanedItem[] {
  if (items.length === 0) return [];

  const positioned = items
    .map((item) => ({ item, ...positionTimedItem(item) }))
    .sort((a, b) => a.top - b.top || a.height - b.height);

  // Greedy lane assignment: for each item, find the first lane where it doesn't overlap
  const lanes: { end: number }[] = [];
  const result: LanedItem[] = [];

  for (const p of positioned) {
    const itemEnd = p.top + p.height;
    let assignedLane = -1;

    for (let i = 0; i < lanes.length; i++) {
      if (lanes[i]!.end <= p.top) {
        assignedLane = i;
        lanes[i]!.end = itemEnd;
        break;
      }
    }

    if (assignedLane === -1) {
      assignedLane = lanes.length;
      lanes.push({ end: itemEnd });
    }

    result.push({ ...p, lane: assignedLane, totalLanes: 0 });
  }

  // Second pass: determine totalLanes for each overlap group
  // Group overlapping items and set totalLanes for the group
  const groups: number[][] = [];
  for (let i = 0; i < result.length; i++) {
    const r = result[i]!;
    let added = false;
    for (const group of groups) {
      const overlaps = group.some((gi) => {
        const g = result[gi]!;
        return r.top < g.top + g.height && r.top + r.height > g.top;
      });
      if (overlaps) {
        group.push(i);
        added = true;
        break;
      }
    }
    if (!added) {
      groups.push([i]);
    }
  }

  for (const group of groups) {
    const maxLane = Math.max(...group.map((i) => result[i]!.lane)) + 1;
    for (const i of group) {
      result[i]!.totalLanes = maxLane;
    }
  }

  return result;
}

/** Get the date range needed for API fetching based on view mode */
export function getDateRangeForView(
  viewMode: CalendarViewMode,
  anchorDate: Dayjs,
): { startDate: string; endDate: string } {
  switch (viewMode) {
    case 'day':
      return {
        startDate: anchorDate.format('YYYY-MM-DD'),
        endDate: anchorDate.format('YYYY-MM-DD'),
      };
    case '3day':
      return {
        startDate: anchorDate.format('YYYY-MM-DD'),
        endDate: anchorDate.add(2, 'day').format('YYYY-MM-DD'),
      };
    case 'week':
      return {
        startDate: anchorDate.startOf('week').format('YYYY-MM-DD'),
        endDate: anchorDate.endOf('week').format('YYYY-MM-DD'),
      };
    case 'month':
      return {
        startDate: anchorDate.startOf('month').subtract(7, 'day').format('YYYY-MM-DD'),
        endDate: anchorDate.endOf('month').add(7, 'day').format('YYYY-MM-DD'),
      };
  }
}

/** Format an hour number to a display label like "6 AM", "12 PM" */
export function formatHourLabel(hour: number): string {
  if (hour === 0) return '12 AM';
  if (hour < 12) return `${hour} AM`;
  if (hour === 12) return '12 PM';
  return `${hour - 12} PM`;
}

/** Get the number of columns and dates for a view mode */
export function getViewDates(viewMode: CalendarViewMode, anchorDate: Dayjs): Dayjs[] {
  switch (viewMode) {
    case 'day':
      return [anchorDate];
    case '3day':
      return [anchorDate, anchorDate.add(1, 'day'), anchorDate.add(2, 'day')];
    case 'week': {
      const start = anchorDate.startOf('week');
      return Array.from({ length: 7 }, (_, i) => start.add(i, 'day'));
    }
    default:
      return [anchorDate];
  }
}

/** Format a time string like "09:30" to "9:30 AM" */
export function formatTimeShort(time: string): string {
  const [h, m] = time.split(':');
  const hour = parseInt(h ?? '0', 10);
  const min = m ?? '00';
  const suffix = hour < 12 ? 'AM' : 'PM';
  const h12 = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
  return min === '00' ? `${h12} ${suffix}` : `${h12}:${min} ${suffix}`;
}
