/**
 * V2 Scenario Renderer
 * Uses EventLayoutEngine from V2 to render events dynamically
 */

// Import the compiled V2 layout engine
// We'll inline the algorithm here for standalone use in browser

// ============================================
// EventLayoutEngine (copied from V2 for browser use)
// ============================================

function eventsOverlap(a, b) {
  return a.start < b.end && a.end > b.start;
}

function eventsWithinThreshold(a, b, thresholdMinutes) {
  const thresholdMs = thresholdMinutes * 60 * 1000;

  const startToStartDiff = Math.abs(a.start.getTime() - b.start.getTime());
  if (startToStartDiff <= thresholdMs) return true;

  const bStartsBeforeAEnds = a.end.getTime() - b.start.getTime();
  if (bStartsBeforeAEnds > 0 && bStartsBeforeAEnds <= thresholdMs) return true;

  const aStartsBeforeBEnds = b.end.getTime() - a.start.getTime();
  if (aStartsBeforeBEnds > 0 && aStartsBeforeBEnds <= thresholdMs) return true;

  return false;
}

function findOverlapGroups(events) {
  if (events.length === 0) return [];

  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
  const used = new Set();
  const groups = [];

  for (const event of sorted) {
    if (used.has(event.id)) continue;

    const group = [event];
    used.add(event.id);

    let expanded = true;
    while (expanded) {
      expanded = false;
      for (const candidate of sorted) {
        if (used.has(candidate.id)) continue;

        const connects = group.some(member => eventsOverlap(member, candidate));

        if (connects) {
          group.push(candidate);
          used.add(candidate.id);
          expanded = true;
        }
      }
    }

    groups.push(group);
  }

  return groups;
}

function findGridCandidates(events, thresholdMinutes) {
  if (events.length === 0) return [];

  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
  const used = new Set();
  const groups = [];

  for (const event of sorted) {
    if (used.has(event.id)) continue;

    const group = [event];
    used.add(event.id);

    let expanded = true;
    while (expanded) {
      expanded = false;
      for (const candidate of sorted) {
        if (used.has(candidate.id)) continue;

        const connects = group.some(member =>
          eventsWithinThreshold(member, candidate, thresholdMinutes)
        );

        if (connects) {
          group.push(candidate);
          used.add(candidate.id);
          expanded = true;
        }
      }
    }

    groups.push(group);
  }

  return groups;
}

function calculateStackLevels(events) {
  const levels = new Map();
  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());

  for (const event of sorted) {
    let maxOverlappingLevel = -1;

    for (const [id, level] of levels) {
      const other = events.find(e => e.id === id);
      if (other && eventsOverlap(event, other)) {
        maxOverlappingLevel = Math.max(maxOverlappingLevel, level);
      }
    }

    levels.set(event.id, maxOverlappingLevel + 1);
  }

  return levels;
}

function allocateColumns(events) {
  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
  const columns = [];

  for (const event of sorted) {
    let placed = false;
    for (const column of columns) {
      const canFit = !column.some(e => eventsOverlap(event, e));
      if (canFit) {
        column.push(event);
        placed = true;
        break;
      }
    }

    if (!placed) {
      columns.push([event]);
    }
  }

  return columns;
}

function calculateEventPosition(start, end, config) {
  const startMinutes = start.getHours() * 60 + start.getMinutes();
  const endMinutes = end.getHours() * 60 + end.getMinutes();

  const dayStartMinutes = config.dayStartHour * 60;
  const minuteHeight = config.hourHeight / 60;

  const top = (startMinutes - dayStartMinutes) * minuteHeight;
  const height = (endMinutes - startMinutes) * minuteHeight;

  return { top, height };
}

function calculateColumnLayout(events, config) {
  const thresholdMinutes = config.gridStartThresholdMinutes ?? 30;

  const result = {
    grids: [],
    stacked: []
  };

  if (events.length === 0) return result;

  const overlapGroups = findOverlapGroups(events);

  for (const overlapGroup of overlapGroups) {
    if (overlapGroup.length === 1) {
      result.stacked.push({
        event: overlapGroup[0],
        stackLevel: 0
      });
      continue;
    }

    const gridSubgroups = findGridCandidates(overlapGroup, thresholdMinutes);

    const largestGridCandidate = gridSubgroups.reduce((max, g) =>
      g.length > max.length ? g : max, gridSubgroups[0]);

    if (largestGridCandidate.length === overlapGroup.length) {
      const columns = allocateColumns(overlapGroup);
      const earliest = overlapGroup.reduce((min, e) =>
        e.start < min.start ? e : min, overlapGroup[0]);
      const position = calculateEventPosition(earliest.start, earliest.end, config);

      result.grids.push({
        events: overlapGroup,
        columns,
        stackLevel: 0,
        position: { top: position.top }
      });
    } else {
      const levels = calculateStackLevels(overlapGroup);
      for (const event of overlapGroup) {
        result.stacked.push({
          event,
          stackLevel: levels.get(event.id) ?? 0
        });
      }
    }
  }

  return result;
}

// ============================================
// Scenario Renderer
// ============================================

const gridConfig = {
  hourHeight: 80,
  dayStartHour: 8,
  dayEndHour: 20,
  snapInterval: 15,
  gridStartThresholdMinutes: 30
};

function formatTime(date) {
  return date.toLocaleTimeString('da-DK', { hour: '2-digit', minute: '2-digit' });
}

function createEventElement(event, config) {
  const element = document.createElement('swp-event');
  element.dataset.eventId = event.id;

  const position = calculateEventPosition(event.start, event.end, config);
  element.style.position = 'absolute';
  element.style.top = `${position.top}px`;
  element.style.height = `${position.height}px`;
  element.style.left = '2px';
  element.style.right = '2px';

  element.innerHTML = `
    <swp-event-time>${formatTime(event.start)} - ${formatTime(event.end)}</swp-event-time>
    <swp-event-title>${event.title}</swp-event-title>
  `;

  return element;
}

function renderGridGroup(layout, config) {
  const group = document.createElement('swp-event-group');
  group.classList.add(`cols-${layout.columns.length}`);
  group.style.top = `${layout.position.top}px`;

  // Stack level styling
  group.dataset.stackLink = JSON.stringify({ stackLevel: layout.stackLevel });
  if (layout.stackLevel > 0) {
    group.style.marginLeft = `${layout.stackLevel * 15}px`;
    group.style.zIndex = `${100 + layout.stackLevel}`;
  }

  // Calculate height
  let maxBottom = 0;
  for (const event of layout.events) {
    const pos = calculateEventPosition(event.start, event.end, config);
    const eventBottom = pos.top + pos.height;
    if (eventBottom > maxBottom) maxBottom = eventBottom;
  }
  group.style.height = `${maxBottom - layout.position.top}px`;

  // Create columns
  layout.columns.forEach(columnEvents => {
    const wrapper = document.createElement('div');
    wrapper.style.position = 'relative';

    columnEvents.forEach(event => {
      const eventEl = createEventElement(event, config);
      const pos = calculateEventPosition(event.start, event.end, config);
      eventEl.style.top = `${pos.top - layout.position.top}px`;
      eventEl.style.left = '0';
      eventEl.style.right = '0';
      wrapper.appendChild(eventEl);
    });

    group.appendChild(wrapper);
  });

  return group;
}

function renderStackedEvent(event, stackLevel, config) {
  const element = createEventElement(event, config);

  element.dataset.stackLink = JSON.stringify({ stackLevel });

  if (stackLevel > 0) {
    element.style.marginLeft = `${stackLevel * 15}px`;
    element.style.zIndex = `${100 + stackLevel}`;
  } else {
    element.style.zIndex = '100';
  }

  return element;
}

export function renderScenario(container, events, config = gridConfig) {
  container.innerHTML = '';

  const layout = calculateColumnLayout(events, config);

  // Render grids
  layout.grids.forEach(grid => {
    const groupEl = renderGridGroup(grid, config);
    container.appendChild(groupEl);
  });

  // Render stacked events
  layout.stacked.forEach(item => {
    const eventEl = renderStackedEvent(item.event, item.stackLevel, config);
    container.appendChild(eventEl);
  });

  return layout;
}

export { calculateColumnLayout, gridConfig };
