import {
  type CopiedShiftCell,
  type ShiftAssignCellVC,
  type ShiftCalendarUser,
} from 'src/types/shifts';

import { type ShiftSelection } from '../contexts/ShiftsSelectionContext';
import { getCellShifts } from './selection';

export function buildShiftCopiedEventProperties(
  copiedData: CopiedShiftCell[],
  days: { key: string }[],
): Record<string, unknown> {
  const copied_cells_count = copiedData.length;
  const copied_shifts_count = copiedData.reduce(
    (sum, cell) => sum + cell.shiftIds.length,
    0,
  );
  const copied_users_count = new Set(copiedData.map(c => c.userId)).size;

  const ordered = [...copiedData].sort(
    (a, b) => a.date.localeCompare(b.date) || a.userId - b.userId,
  );
  const isEmpty = (c: CopiedShiftCell) => c.shiftIds.length === 0;
  let start = 0;
  while (start < ordered.length && isEmpty(ordered[start])) start++;
  const has_empty_cells_at_start = start > 0;
  let end = ordered.length - 1;
  while (end >= 0 && isEmpty(ordered[end])) end--;
  const has_empty_cells_at_end = end < ordered.length - 1;
  const middle = ordered.slice(start, end + 1);
  const has_empty_cells_in_middle = middle.some(isEmpty);

  const byUser = new Map<number, Set<string>>();
  for (const cell of copiedData) {
    let dateSet = byUser.get(cell.userId);
    if (!dateSet) {
      dateSet = new Set<string>();
      byUser.set(cell.userId, dateSet);
    }
    dateSet.add(cell.date);
  }
  const users_positions = [...byUser.entries()]
    .sort(([a], [b]) => a - b)
    .map(([, dates]) =>
      [...dates]
        .map(date => days.findIndex(d => d.key === date) + 1)
        .filter(p => p >= 1)
        .sort((a, b) => a - b),
    );

  const selected_users_count = users_positions.length;

  // Users that have a full week (positions 1..7) selected
  const FULL_WEEK_LENGTH = 7;
  const users_all_week_selected: number[] = [];
  users_positions.forEach((positions, index) => {
    if (positions.length !== FULL_WEEK_LENGTH) return;
    const first = positions[0];
    const last = positions[positions.length - 1];
    const isContiguous = last - first + 1 === positions.length;
    if (isContiguous && first === 1 && last === FULL_WEEK_LENGTH) {
      // store row position as 1-based index
      users_all_week_selected.push(index + 1);
    }
  });
  const users_all_week_selected_count = users_all_week_selected.length;

  return {
    copied_cells_count,
    copied_shifts_count,
    copied_users_count,
    selected_users_count,
    has_empty_cells_at_start,
    has_empty_cells_at_end,
    has_empty_cells_in_middle,
    users_positions,
    users_all_week_selected,
    users_all_week_selected_count,
  };
}

export function buildShiftPastedEventProperties(
  pastedData: CopiedShiftCell[],
  days: { key: string }[],
): Record<string, unknown> {
  const dayKeys = new Set(days.map(d => d.key));
  const visiblePastedCells = pastedData.filter(c => dayKeys.has(c.date));
  const pasted_cells_count = visiblePastedCells.length;

  const byUser = new Map<number, Set<string>>();
  for (const cell of visiblePastedCells) {
    let dateSet = byUser.get(cell.userId);
    if (!dateSet) {
      dateSet = new Set<string>();
      byUser.set(cell.userId, dateSet);
    }
    dateSet.add(cell.date);
  }
  const users_positions = [...byUser.entries()]
    .sort(([a], [b]) => a - b)
    .map(([, dates]) =>
      [...dates]
        .map(date => days.findIndex(d => d.key === date) + 1)
        .filter(p => p >= 1)
        .sort((a, b) => a - b),
    );
  const selected_users_count = users_positions.length;

  const uniqueDates = [...new Set(visiblePastedCells.map(c => c.date))];
  const columnIndices = uniqueDates
    .map(date => days.findIndex(d => d.key === date) + 1)
    .filter(i => i >= 1)
    .sort((a, b) => a - b);
  const has_gaps_in_selection =
    columnIndices.length > 0 &&
    columnIndices[columnIndices.length - 1] - columnIndices[0] + 1 !==
      columnIndices.length;

  const FULL_WEEK_LENGTH = 7;
  const users_all_week_selected: number[] = [];
  users_positions.forEach((positions, index) => {
    if (positions.length !== FULL_WEEK_LENGTH) return;
    const first = positions[0];
    const last = positions[positions.length - 1];
    const isContiguous = last - first + 1 === positions.length;
    if (isContiguous && first === 1 && last === FULL_WEEK_LENGTH) {
      users_all_week_selected.push(index + 1);
    }
  });
  const users_all_week_selected_count = users_all_week_selected.length;

  return {
    pasted_cells_count,
    has_gaps_in_selection,
    users_positions,
    selected_users_count,
    users_all_week_selected,
    users_all_week_selected_count,
  };
}

/** Builds CopiedShiftCell[] from current selection for analytics when copy is invalid. */
export function buildAttemptedCopiedData(
  selectedCells: ShiftAssignCellVC[],
  selectedShifts: Map<number, ShiftSelection>,
  registers: ShiftCalendarUser[],
): CopiedShiftCell[] {
  const byKey = new Map<string, CopiedShiftCell>();

  selectedCells.forEach(cell => {
    const key = `${cell.userId}-${cell.date}`;
    if (byKey.has(key)) return;
    const cellShifts = getCellShifts(cell, registers);
    byKey.set(key, {
      userId: cell.userId,
      date: cell.date,
      shiftIds: [...cellShifts],
    });
  });

  selectedShifts.forEach(shift => {
    const key = `${shift.userId}-${shift.date}`;
    const existing = byKey.get(key);
    if (existing) {
      if (!existing.shiftIds.includes(shift.shiftId)) {
        existing.shiftIds.push(shift.shiftId);
      }
      return;
    }
    byKey.set(key, {
      userId: shift.userId,
      date: shift.date,
      shiftIds: [shift.shiftId],
    });
  });

  return [...byKey.values()];
}
