// state.ts - Peak Holder с фиксированным временем удержания

interface AppState {
    maxPoints: number;
    signalHistory: number[];
    lastBufferSize: number;

    // Peak Holder для амплитуды
    peakValue: number;           // Текущее удерживаемое пиковое значение амплитуды
    currentValue: number;        // Текущий максимум из буфера
    peakTimer: number | null;    // Таймер для сброса пика амплитуды
    peakHoldTime: number;        // Время удержания пика в миллисекундах
    peakLocked: boolean;         // Заблокирован ли пик (не сбрасывается до таймера)

    // Peak Holder для уровня сигнала
    peakSignalLevel: number;
    currentSignalLevel: number;
    signalPeakTimer: number | null;
    signalPeakHoldTime: number;
    signalPeakLocked: boolean;

    hasPeak: boolean;
    lastMaxSignal: number;
}

type PeakHolderListener = () => void;

export const state: AppState = {
    maxPoints: 1000,
    signalHistory: [],
    lastBufferSize: 0,

    peakValue: 0,
    currentValue: 0,
    peakTimer: null,
    peakHoldTime: 3000,
    peakLocked: false,

    peakSignalLevel: 0,
    currentSignalLevel: 0,
    signalPeakTimer: null,
    signalPeakHoldTime: 3000,
    signalPeakLocked: false,

    hasPeak: false,
    lastMaxSignal: 0,
};

let peakHolderListener: PeakHolderListener | null = null;

// ============================================
// ПУБЛИЧНЫЕ ФУНКЦИИ
// ============================================

export function setPeakHolderListener(listener: PeakHolderListener | null): void {
    peakHolderListener = listener;
}

function notifyPeakHolderChange(): void {
    if (peakHolderListener) {
        peakHolderListener();
    }
}

/**
 * Обновление пикового значения амплитуды
 * @param currentMax - текущий максимум из буфера (в процентах 0-100)
 * @returns пиковое значение
 */
export function updatePeakHolder(currentMax: number): number {
    state.currentValue = currentMax;
    state.lastMaxSignal = currentMax;

    // Если пик заблокирован - ничего не меняем, только обновляем currentValue
    if (state.peakLocked) {
        return state.peakValue;
    }

    // Если новое значение БОЛЬШЕ текущего пика - обновляем пик и блокируем
    if (currentMax > state.peakValue) {
        state.peakValue = currentMax;
        state.hasPeak = true;
        state.peakLocked = true;
        scheduleAmplitudePeakRelease();
        notifyPeakHolderChange();
        return state.peakValue;
    }

    // Если новое значение МЕНЬШЕ или РАВНО - ничего не делаем
    return state.peakValue;
}

/**
 * Обновление пикового уровня сигнала
 * @param currentMaxLevel - текущий максимум уровня из буфера (0-3)
 * @returns пиковый уровень
 */
export function updateSignalPeakHolder(currentMaxLevel: number): number {
    state.currentSignalLevel = currentMaxLevel;

    if (state.signalPeakLocked) {
        return state.peakSignalLevel;
    }

    if (currentMaxLevel > state.peakSignalLevel) {
        state.peakSignalLevel = currentMaxLevel;
        state.hasPeak = true;
        state.signalPeakLocked = true;
        scheduleSignalPeakRelease();
        notifyPeakHolderChange();
        return state.peakSignalLevel;
    }

    return state.peakSignalLevel;
}

// ============================================
// ВНУТРЕННИЕ ФУНКЦИИ
// ============================================

function scheduleAmplitudePeakRelease(): void {
    if (state.peakTimer !== null) {
        clearTimeout(state.peakTimer);
        state.peakTimer = null;
    }

    state.peakTimer = window.setTimeout(() => {
        // Сбрасываем пик до текущего значения
        state.peakValue = state.currentValue;
        state.peakTimer = null;
        state.hasPeak = false;
        state.peakLocked = false;
        notifyPeakHolderChange();
    }, state.peakHoldTime);
}

function scheduleSignalPeakRelease(): void {
    if (state.signalPeakTimer !== null) {
        clearTimeout(state.signalPeakTimer);
        state.signalPeakTimer = null;
    }

    state.signalPeakTimer = window.setTimeout(() => {
        state.peakSignalLevel = state.currentSignalLevel;
        state.signalPeakTimer = null;
        state.hasPeak = false;
        state.signalPeakLocked = false;
        notifyPeakHolderChange();
    }, state.signalPeakHoldTime);
}

// ============================================
// ОСТАЛЬНЫЕ ФУНКЦИИ
// ============================================

export function setSignalPeakHoldTime(ms: number): void {
    state.signalPeakHoldTime = ms;
}

export function getSignalPeakInfo(): { peak: number; current: number; timerActive: boolean } {
    return {
        peak: state.peakSignalLevel,
        current: state.currentSignalLevel,
        timerActive: state.signalPeakTimer !== null,
    };
}

export function addSignal(value: number): void {
    state.signalHistory.push(value);
    if (state.signalHistory.length > state.maxPoints) {
        state.signalHistory = state.signalHistory.slice(-state.maxPoints);
    }
}

export function forceResetSignalPeak(): void {
    if (state.signalPeakTimer !== null) {
        clearTimeout(state.signalPeakTimer);
        state.signalPeakTimer = null;
    }
    state.peakSignalLevel = 0;
    state.currentSignalLevel = 0;
    state.hasPeak = false;
    state.lastMaxSignal = 0;
    state.signalPeakLocked = false;
    notifyPeakHolderChange();
}

export function forceResetPeak(): void {
    if (state.peakTimer !== null) {
        clearTimeout(state.peakTimer);
        state.peakTimer = null;
    }
    state.peakValue = 0;
    state.currentValue = 0;
    state.hasPeak = false;
    state.lastMaxSignal = 0;
    state.peakLocked = false;
    forceResetSignalPeak();
    notifyPeakHolderChange();
}

export function addSignals(values: number[], bufferSize: number): void {
    if (!Array.isArray(values) || values.length === 0) return;

    const newBytes = bufferSize - state.lastBufferSize;

    if (newBytes > 0 && newBytes <= values.length) {
        const fresh = values.slice(-newBytes);
        const decoded = fresh.map(b => b & 0x3F);
        state.signalHistory.push(...decoded);
    }

    state.lastBufferSize = bufferSize;

    if (state.signalHistory.length > state.maxPoints) {
        state.signalHistory = state.signalHistory.slice(-state.maxPoints);
    }
}

export function resetBufferTracking(): void {
    state.lastBufferSize = 0;
    forceResetPeak();
}