/** Русский алфавит (33 буквы), порядок как в типичной школьной нумерации. */
export const HALL_SEAT_CYRILLIC_ALPHABET = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ';

const CYRILLIC_LIST = [...HALL_SEAT_CYRILLIC_ALPHABET];
const CYRILLIC_BASE = CYRILLIC_LIST.length; // 33

function normalizeCyrillicChar(c: string): string | null {
    if (!c) {
        return null;
    }
    const u = c === 'ё' || c === 'Ё' ? 'Ё' : c.toUpperCase();
    return HALL_SEAT_CYRILLIC_ALPHABET.includes(u) ? u : null;
}

/** Excel-подобный разбор латинской последовательности (A…Z, AA…). */
export function hallLatinBijectiveDecode(s: string): number | null {
    const u = s.toUpperCase();
    if (!u.length || !/^[A-Z]+$/.test(u)) {
        return null;
    }
    let n = 0;
    for (let i = 0; i < u.length; i++) {
        const ord = u.charCodeAt(i)! - 64;
        if (ord < 1 || ord > 26) {
            return null;
        }
        n = n * 26 + ord;
    }
    return n;
}

export function hallLatinBijectiveEncode(n: number): string {
    if (!Number.isFinite(n) || n < 1) {
        return '';
    }
    let x = Math.floor(n);
    let s = '';
    while (x > 0) {
        x--;
        s = String.fromCharCode(65 + (x % 26)) + s;
        x = Math.floor(x / 26);
    }
    return s;
}

export function hallCyrillicBijectiveDecode(str: string): number | null {
    const chars = [...(str.trim())];
    if (!chars.length) {
        return null;
    }
    let n = 0;
    for (const ch of chars) {
        const norm = normalizeCyrillicChar(ch);
        if (!norm) {
            return null;
        }
        const idx = HALL_SEAT_CYRILLIC_ALPHABET.indexOf(norm);
        n = n * CYRILLIC_BASE + (idx + 1);
    }
    return n;
}

export function hallCyrillicBijectiveEncode(n: number): string {
    if (!Number.isFinite(n) || n < 1) {
        return '';
    }
    let x = Math.floor(n);
    let s = '';
    while (x > 0) {
        x--;
        s = CYRILLIC_LIST[x % CYRILLIC_BASE]! + s;
        x = Math.floor(x / CYRILLIC_BASE);
    }
    return s;
}

export type HallSeatParsedStart =
    | { kind: 'numeric'; base: number }
    | { kind: 'latin'; start1: number }
    | { kind: 'cyrillic'; start1: number };

const DIGITS_ONLY = /^-?\d+$/;
const LATIN_ONLY = /^[A-Za-z]+$/;

function isCyrillicOnly(str: string): boolean {
    return /^[А-Яа-яЁё]+$/.test(str);
}

/**
 * Разбор поля «Начать с»: только цифры / только латиница / только кириллица.
 */
export function parseHallSeatStart(raw: string): HallSeatParsedStart | null {
    const trimmed = raw.trim();
    if (!trimmed) {
        return null;
    }
    if (DIGITS_ONLY.test(trimmed)) {
        const base = Number.parseInt(trimmed, 10);
        if (!Number.isSafeInteger(base)) {
            return null;
        }
        return { kind: 'numeric', base };
    }
    if (LATIN_ONLY.test(trimmed)) {
        const start1 = hallLatinBijectiveDecode(trimmed);
        if (start1 == null || start1 < 1) {
            return null;
        }
        return { kind: 'latin', start1 };
    }
    if (isCyrillicOnly(trimmed)) {
        const start1 = hallCyrillicBijectiveDecode(trimmed);
        if (start1 == null || start1 < 1) {
            return null;
        }
        return { kind: 'cyrillic', start1 };
    }
    return null;
}

/** Метка с отступом offset от старта (0 — первое место / первый ряд). */
export function hallSeatLabelAt(parsed: HallSeatParsedStart, offset: number): string {
    if (!Number.isFinite(offset) || offset < 0) {
        return '';
    }
    const o = Math.floor(offset);
    switch (parsed.kind) {
        case 'numeric':
            return String(parsed.base + o);
        case 'latin':
            return hallLatinBijectiveEncode(parsed.start1 + o);
        case 'cyrillic':
            return hallCyrillicBijectiveEncode(parsed.start1 + o);
        default: {
            const _n: never = parsed;
            return _n;
        }
    }
}
