import type { TguPlanUi, TimelineLink, TimelinePlanSegment, TimelineRange, TimelineRow } from "../../model/timelineTypes";

export const TIMELINE_LABEL_WIDTH = 220;
export const TIMELINE_ROW_HEIGHT = 58;
export const TIMELINE_AXIS_HEIGHT = 46;
export const TIMELINE_BOTTOM_PADDING = 18;
export const TIMELINE_LANE_STEP = 12;

export function timeToX(timeMs: number, range: TimelineRange, timelineWidth: number): number {
  return ((timeMs - range.fromMs) / (range.toMs - range.fromMs)) * timelineWidth;
}

export function clipPlanToRange(plan: TguPlanUi, range: TimelineRange): { startMs: number; endMs: number } | null {
  if (plan.endMs < range.fromMs || plan.startMs > range.toMs) {
    return null;
  }

  return {
    startMs: Math.max(plan.startMs, range.fromMs),
    endMs: Math.min(plan.endMs, range.toMs)
  };
}

export function buildTimelineSegments(
  rows: TimelineRow[],
  range: TimelineRange,
  timelineWidth: number
): TimelinePlanSegment[] {
  const segments: TimelinePlanSegment[] = [];

  rows.forEach((row, rowIndex) => {
    const visiblePlans = row.plans
      .map((plan) => ({ plan, clipped: clipPlanToRange(plan, range) }))
      .filter((item): item is { plan: TguPlanUi; clipped: { startMs: number; endMs: number } } => item.clipped !== null)
      .sort((a, b) => a.plan.startMs - b.plan.startMs || a.plan.endMs - b.plan.endMs);

    visiblePlans.forEach((item, planIndex) => {
      const x = timeToX(item.clipped.startMs, range, timelineWidth);
      const x2 = timeToX(item.clipped.endMs, range, timelineWidth);
      segments.push({
        plan: item.plan,
        rowIndex,
        laneOffset: timelineLaneOffset(planIndex),
        x,
        x2,
        width: Math.max(3, x2 - x)
      });
    });
  });

  return segments;
}

export function timelineLaneOffset(index: number): number {
  return [0, -1, 0, 1][index % 4] * TIMELINE_LANE_STEP;
}

export function buildSequentialLinks(rows: TimelineRow[]): TimelineLink[] {
  const links: TimelineLink[] = [];

  for (const row of rows) {
    const sorted = [...row.plans].sort((a, b) => a.startMs - b.startMs || a.endMs - b.endMs);
    for (let index = 0; index < sorted.length - 1; index += 1) {
      links.push({
        spacecraftId: row.spacecraftId,
        fromPlanId: sorted[index].planId,
        toPlanId: sorted[index + 1].planId
      });
    }
  }

  return links;
}

export function buildTimeTicks(range: TimelineRange, targetCount = 8): number[] {
  const span = range.toMs - range.fromMs;
  const roughStep = span / targetCount;
  const candidates = [
    15 * 60_000,
    30 * 60_000,
    60 * 60_000,
    2 * 60 * 60_000,
    3 * 60 * 60_000,
    6 * 60 * 60_000,
    12 * 60 * 60_000,
    24 * 60 * 60_000
  ];
  const step = candidates.find((candidate) => candidate >= roughStep) ?? 24 * 60 * 60_000;
  const first = Math.ceil(range.fromMs / step) * step;
  const ticks: number[] = [];

  for (let tick = first; tick <= range.toMs; tick += step) {
    ticks.push(tick);
  }

  return ticks;
}

export function timelineHeight(rowCount: number): number {
  return TIMELINE_AXIS_HEIGHT + rowCount * TIMELINE_ROW_HEIGHT + TIMELINE_BOTTOM_PADDING;
}
