export interface TimeWindow {
  start: string;
  end: string;
}

export function parseTimeToMinutes(s: string): number {
  if (typeof s !== 'string') {
    throw new Error(`Invalid time: ${String(s)}`);
  }
  const match: RegExpMatchArray | null = s.match(/^(\d{1,2}):(\d{2})$/);
  if (match === null) {
    throw new Error(`Invalid time format: ${s}`);
  }
  const hours: number = parseInt(match[1], 10);
  const minutes: number = parseInt(match[2], 10);
  if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
    throw new Error(`Invalid time value: ${s}`);
  }
  return hours * 60 + minutes;
}

function resolveWindow(win: TimeWindow): { startMin: number; endMin: number } {
  const startMin: number = parseTimeToMinutes(win.start);
  let endMin: number = parseTimeToMinutes(win.end);
  if (endMin <= startMin) {
    endMin += 1440;
  }
  return { startMin, endMin };
}

export function computeSlicePosition(
  parent: TimeWindow,
  slice: TimeWindow
): { leftPct: number; widthPct: number } | null {
  const parentRange: { startMin: number; endMin: number } = resolveWindow(parent);
  const parentDuration: number = parentRange.endMin - parentRange.startMin;
  if (parentDuration <= 0) {
    return null;
  }

  const sliceStartRaw: number = parseTimeToMinutes(slice.start);
  let sliceEndRaw: number = parseTimeToMinutes(slice.end);
  if (sliceEndRaw <= sliceStartRaw) {
    sliceEndRaw += 1440;
  }

  const candidateOffsets: number[] = [0, 1440];
  let bestOverlap: { start: number; end: number } | null = null;

  for (const offset of candidateOffsets) {
    const s: number = sliceStartRaw + offset;
    const e: number = sliceEndRaw + offset;
    const overlapStart: number = Math.max(s, parentRange.startMin);
    const overlapEnd: number = Math.min(e, parentRange.endMin);
    if (overlapEnd > overlapStart) {
      if (bestOverlap === null || (overlapEnd - overlapStart) > (bestOverlap.end - bestOverlap.start)) {
        bestOverlap = { start: overlapStart, end: overlapEnd };
      }
    }
  }

  if (bestOverlap === null) {
    return null;
  }

  const leftPct: number = Math.max(
    0,
    Math.min(100, ((bestOverlap.start - parentRange.startMin) / parentDuration) * 100)
  );
  const widthPct: number = Math.max(
    0,
    Math.min(100 - leftPct, ((bestOverlap.end - bestOverlap.start) / parentDuration) * 100)
  );

  if (widthPct <= 0) {
    return null;
  }

  return { leftPct, widthPct };
}

export type SessionStatusForStyle =
  | 'pending_assignment'
  | 'proposed'
  | 'approved'
  | 'unstaffed'
  | 'cancelled';

export interface SliceStyle {
  bg: string;
  border: string;
  label: string;
  textColor: string;
}

export function styleForSessionStatus(status: SessionStatusForStyle): SliceStyle {
  switch (status) {
    case 'pending_assignment':
      return {
        bg: 'rgba(255, 167, 38, 0.2)',
        border: '2px solid #FFA726',
        label: 'Offen',
        textColor: '#6D4C00',
      };
    case 'proposed':
      return {
        bg: 'rgba(25, 118, 210, 0.15)',
        border: '2px dashed #1976D2',
        label: 'Vorgeschlagen',
        textColor: '#0D3C78',
      };
    case 'approved':
      return {
        bg: '#388E3C',
        border: '2px solid #2E7031',
        label: 'Bestätigt',
        textColor: '#FFFFFF',
      };
    case 'unstaffed':
      return {
        bg: 'rgba(211, 47, 47, 0.2)',
        border: '2px solid #D32F2F',
        label: 'Unbesetzt',
        textColor: '#7A1818',
      };
    case 'cancelled':
      return {
        bg: 'rgba(158, 158, 158, 0.15)',
        border: '2px dashed #9E9E9E',
        label: 'Abgesagt',
        textColor: '#424242',
      };
  }
}
