import type { HallElementType } from '@/api/types';

/**
 * Направление обхода.
 * Для **номеров рядов**: сверху/снизу — горизонтальные ряды; слева/справа — вертикальные колонки как «линии».
 * Для **нумерации мест**: слева/справа — порядок мест в горизонтальном ряду (→ 1234 в строке); сверху/снизу — порядок рядов.
 */
export type HallSeatGroupPurpose = 'seat_rows' | 'seat_numbers';
export type HallSeatFillDirection =
    | 'top_bottom'
    | 'bottom_top'
    | 'left_right'
    | 'right_left';

export const HALL_SEAT_FILL_DIRECTIONS: readonly HallSeatFillDirection[] = [
    'top_bottom',
    'bottom_top',
    'left_right',
    'right_left',
] as const;

/** Направление по умолчанию в форме «Номера рядов». */
export const HALL_SEAT_FILL_DIRECTION_DEFAULT_ROWS: HallSeatFillDirection = 'top_bottom';
/** Направление по умолчанию в форме «Нумерация мест». */
export const HALL_SEAT_FILL_DIRECTION_DEFAULT_SEAT_NUMBERS: HallSeatFillDirection = 'left_right';

/** Ключи в `local.ts` для подписей в селекте */
export const HALL_SEAT_FILL_DIRECTION_LANG_KEY: Record<HallSeatFillDirection, string> = {
    top_bottom: 'hall_seat_dir_top_bottom',
    bottom_top: 'hall_seat_dir_bottom_top',
    left_right: 'hall_seat_dir_left_right',
    right_left: 'hall_seat_dir_right_left',
};

function meanCoord(line: HallElementType[], axis: 'x' | 'y'): number {
    return line.reduce((s, p) => s + (axis === 'y' ? p.y : p.x), 0) / line.length;
}

/** Склейка мест в линии по одной оси (ряд по Y или колонка по X). */
export function clusterHallSeatsByAxis(
    seats: HallElementType[],
    axis: 'x' | 'y',
    tolerance: number,
): HallElementType[][] {
    if (!seats.length) {
        return [];
    }
    const sorted = [...seats].sort((a, b) => (axis === 'y' ? a.y - b.y : a.x - b.x));
    const lines: HallElementType[][] = [];
    for (const seat of sorted) {
        const lastLine = lines[lines.length - 1];
        if (!lastLine) {
            lines.push([seat]);
            continue;
        }
        const mean = meanCoord(lastLine, axis);
        const v = axis === 'y' ? seat.y : seat.x;
        if (Math.abs(v - mean) <= tolerance) {
            lastLine.push(seat);
        } else {
            lines.push([seat]);
        }
    }
    return lines;
}

function hallSeatsRowLinesTopBottom(seats: HallElementType[], tolerance: number): HallElementType[][] {
    const lines = clusterHallSeatsByAxis(seats, 'y', tolerance);
    const sortedLines = [...lines].sort((a, b) => meanCoord(a, 'y') - meanCoord(b, 'y'));
    return sortedLines.map((line) => [...line].sort((a, b) => a.x - b.x));
}

function hallSeatsRowLinesBottomTop(seats: HallElementType[], tolerance: number): HallElementType[][] {
    const lines = clusterHallSeatsByAxis(seats, 'y', tolerance);
    const sortedLines = [...lines].sort((a, b) => meanCoord(b, 'y') - meanCoord(a, 'y'));
    return sortedLines.map((line) => [...line].sort((a, b) => a.x - b.x));
}

function hallSeatsColumnLinesLeftRight(seats: HallElementType[], tolerance: number): HallElementType[][] {
    const lines = clusterHallSeatsByAxis(seats, 'x', tolerance);
    const sortedLines = [...lines].sort((a, b) => meanCoord(a, 'x') - meanCoord(b, 'x'));
    return sortedLines.map((line) => [...line].sort((a, b) => a.y - b.y));
}

function hallSeatsColumnLinesRightLeft(seats: HallElementType[], tolerance: number): HallElementType[][] {
    const lines = clusterHallSeatsByAxis(seats, 'x', tolerance);
    const sortedLines = [...lines].sort((a, b) => meanCoord(b, 'x') - meanCoord(a, 'x'));
    return sortedLines.map((line) => [...line].sort((a, b) => a.y - b.y));
}

/** Горизонтальные ряды сверху вниз, в ряду справа налево (для нумерации мест). */
function hallSeatsRowLinesTopBottomRtl(seats: HallElementType[], tolerance: number): HallElementType[][] {
    const lines = clusterHallSeatsByAxis(seats, 'y', tolerance);
    const sortedLines = [...lines].sort((a, b) => meanCoord(a, 'y') - meanCoord(b, 'y'));
    return sortedLines.map((line) => [...line].sort((a, b) => b.x - a.x));
}

/**
 * Линии в порядке обхода; внутри линии — порядок нумерации / присвоения ряда.
 * @param purpose для нумерации мест «слева/справа» трактуются как порядок в горизонтальном ряду; для рядов — как колонки.
 */
export function hallSeatsGroupedLinesOrdered(
    seats: HallElementType[],
    direction: HallSeatFillDirection,
    tolerance: number,
    purpose: HallSeatGroupPurpose = 'seat_rows',
): HallElementType[][] {
    if (purpose === 'seat_numbers') {
        switch (direction) {
            case 'top_bottom':
                return hallSeatsRowLinesTopBottom(seats, tolerance);
            case 'bottom_top':
                return hallSeatsRowLinesBottomTop(seats, tolerance);
            case 'left_right':
                return hallSeatsRowLinesTopBottom(seats, tolerance);
            case 'right_left':
                return hallSeatsRowLinesTopBottomRtl(seats, tolerance);
        }
    }

    switch (direction) {
        case 'top_bottom':
            return hallSeatsRowLinesTopBottom(seats, tolerance);
        case 'bottom_top':
            return hallSeatsRowLinesBottomTop(seats, tolerance);
        case 'left_right':
            return hallSeatsColumnLinesLeftRight(seats, tolerance);
        case 'right_left':
            return hallSeatsColumnLinesRightLeft(seats, tolerance);
    }
}
