/**
 * Calibration Manager
 * Handles VNA calibration workflow
 */

import { Debouncer, RequestGuard, ButtonState } from '../utils.js';
import { renderIcons } from '../icons.js';
import { apiGet, apiPost, apiDelete, buildUrl } from '../api-client.js';
import { API, TIMING, CALIBRATION_STANDARDS, NOTIFICATION_TYPES } from '../constants.js';

const { SUCCESS, ERROR, INFO } = NOTIFICATION_TYPES;

export class CalibrationManager {
    constructor(notifications) {
        this.notifications = notifications;
        this.workingCalibration = null;
        this.currentCalibration = null;
        this.disabledStandards = new Set();
        this.elements = {};
        this.debouncer = new Debouncer();
        this.reqGuard = new RequestGuard();
        this.currentPreset = null;

        this.handleStartCalibration = this.handleStartCalibration.bind(this);
        this.handleSaveCalibration = this.handleSaveCalibration.bind(this);
        this.handleSetCalibration = this.handleSetCalibration.bind(this);
        this.handleCalibrationChange = this.handleCalibrationChange.bind(this);
        this.handleDeleteCalibration = this.handleDeleteCalibration.bind(this);
        this.handleClearCalibration = this.handleClearCalibration.bind(this);
    }

    init(elements) {
        this.elements = elements;
        this.elements.startCalibrationBtn?.addEventListener('click', this.handleStartCalibration);
        this.elements.saveCalibrationBtn?.addEventListener('click', this.handleSaveCalibration);
        this.elements.calibrationDropdown?.addEventListener('change', this.handleCalibrationChange);
        this.elements.setCalibrationBtn?.addEventListener('click', this.handleSetCalibration);
        this.elements.deleteCalibrationBtn?.addEventListener('click', this.handleDeleteCalibration);
        this.elements.clearCalibrationBtn?.addEventListener('click', this.handleClearCalibration);

        this.elements.calibrationNameInput?.addEventListener('input', () => {
            const hasName = this.elements.calibrationNameInput.value.trim().length > 0;
            const isComplete = this.workingCalibration && this.workingCalibration.is_complete;
            this.elements.saveCalibrationBtn.disabled = !hasName || !isComplete;
        });
    }

    destroy() {
        this.elements.startCalibrationBtn?.removeEventListener('click', this.handleStartCalibration);
        this.elements.saveCalibrationBtn?.removeEventListener('click', this.handleSaveCalibration);
        this.elements.calibrationDropdown?.removeEventListener('change', this.handleCalibrationChange);
        this.elements.setCalibrationBtn?.removeEventListener('click', this.handleSetCalibration);
        this.elements.deleteCalibrationBtn?.removeEventListener('click', this.handleDeleteCalibration);
        this.elements.clearCalibrationBtn?.removeEventListener('click', this.handleClearCalibration);
        this.resetCaptureState();
    }

    setCurrentPreset(preset) {
        this.currentPreset = preset;
        if (preset) {
            this.elements.startCalibrationBtn.disabled = false;
            this.loadCalibrations();
        } else {
            this.elements.startCalibrationBtn.disabled = true;
            this.reset();
        }
    }

    async loadWorkingCalibration() {
        try {
            const working = await apiGet(API.SETTINGS.WORKING_CALIBRATION);
            this.updateWorking(working);
        } catch (e) {
            console.error('Working calibration load failed:', e);
        }
    }

    async loadCalibrations() {
        if (!this.currentPreset) return;
        try {
            const url = buildUrl(API.SETTINGS.CALIBRATIONS, {
                preset_filename: this.currentPreset.filename
            });
            const calibrations = await apiGet(url);
            this.populateDropdown(calibrations);
        } catch (e) {
            console.error('Calibrations load failed:', e);
        }
    }

    populateDropdown(calibrations) {
        const dd = this.elements.calibrationDropdown;
        dd.innerHTML = '';

        if (!calibrations.length) {
        dd.innerHTML = '<option value="">Калибровки отсутствуют</option>';
            dd.disabled = true;
            this.elements.setCalibrationBtn.disabled = true;
            this.elements.viewPlotsBtn.disabled = true;
            if (this.elements.deleteCalibrationBtn) {
                this.elements.deleteCalibrationBtn.disabled = true;
            }
            if (this.elements.clearCalibrationBtn) {
                this.elements.clearCalibrationBtn.disabled = true;
            }
            return;
        }

        dd.innerHTML = '<option value="">Выберите калибровку...</option>';
        calibrations.forEach(c => {
            const opt = document.createElement('option');
            opt.value = c.name;
            opt.textContent = `${c.name} ${c.is_complete ? '✔' : '?'}`;
            dd.appendChild(opt);
        });

        dd.disabled = false;
        this.elements.setCalibrationBtn.disabled = true;
        this.elements.viewPlotsBtn.disabled = true;
        if (this.elements.deleteCalibrationBtn) {
            this.elements.deleteCalibrationBtn.disabled = true;
        }
        if (this.elements.clearCalibrationBtn) {
            this.elements.clearCalibrationBtn.disabled = !this.currentCalibration;
        }
    }

    updateWorking(working) {
        this.workingCalibration = working;
        if (working.active) {
            this.showSteps(working);
        } else {
            this.hideSteps();
        }
    }

    showSteps(working) {
        this.elements.calibrationSteps.style.display = 'block';
        this.elements.progressText.textContent = working.progress || '0/0';

        this.renderStandardButtons(working);

        const hasName = this.elements.calibrationNameInput.value.trim().length > 0;
        this.elements.saveCalibrationBtn.disabled = !hasName || !working.is_complete;
        this.elements.calibrationNameInput.disabled = false;

        const hasCompleted = (working.completed_standards || []).length > 0;
        if (this.elements.viewCurrentPlotsBtn) {
            this.elements.viewCurrentPlotsBtn.disabled = !hasCompleted;
        }
    }

    hideSteps() {
        this.elements.calibrationSteps.style.display = 'none';
        this.elements.calibrationStandards.innerHTML = '';
        if (this.elements.viewCurrentPlotsBtn) {
            this.elements.viewCurrentPlotsBtn.disabled = true;
        }
    }

    renderStandardButtons(working) {
        const container = this.elements.calibrationStandards;
        container.innerHTML = '';

        const all = this.getStandardsForMode();
        const completed = working.completed_standards || [];
        const missing = working.missing_standards || [];

        all.forEach(std => {
            const btn = document.createElement('button');
            btn.className = 'btn calibration-standard-btn';
            btn.dataset.standard = std;

            const isCompleted = completed.includes(std);
            const isMissing = missing.includes(std);
            const capturing = this.disabledStandards.has(std);

            if (capturing) {
                btn.classList.add('btn--warning');
                btn.innerHTML = `<span data-icon="clock"></span> Снятие ${std.toUpperCase()}...`;
                btn.disabled = true;
                btn.title = 'Стандарт сейчас снимается';
            } else if (isCompleted) {
                btn.classList.add('btn--success');
                btn.innerHTML = `<span data-icon="check"></span> ${std.toUpperCase()}`;
                btn.disabled = false;
                btn.title = 'Нажмите, чтобы переснять стандарт';
            } else if (isMissing) {
                btn.classList.add('btn--primary');
                btn.innerHTML = `<span data-icon="radio"></span> Снять ${std.toUpperCase()}`;
                btn.disabled = false;
                btn.title = 'Нажмите, чтобы снять стандарт';
            } else {
                btn.classList.add('btn--secondary');
                btn.innerHTML = `${std.toUpperCase()}`;
                btn.disabled = true;
            }

            btn.addEventListener('click', () => this.captureStandard(std));
            container.appendChild(btn);
        });

        renderIcons(container);
    }

    getStandardsForMode() {
        if (!this.currentPreset || !this.currentPreset.mode) return [];
        const modeKey = this.currentPreset.mode.toUpperCase();
        return CALIBRATION_STANDARDS[modeKey] || [];
    }

    handleCalibrationChange() {
        const v = this.elements.calibrationDropdown.value;
        this.elements.setCalibrationBtn.disabled = !v;
        this.elements.viewPlotsBtn.disabled = !v;
        if (this.elements.deleteCalibrationBtn) {
            this.elements.deleteCalibrationBtn.disabled = !v;
        }
    }

    async handleStartCalibration() {
        if (!this.currentPreset) return;

        this.debouncer.debounce('start-calibration', () =>
            this.reqGuard.runExclusive('start-calibration', async () => {
                try {
                    ButtonState.set(this.elements.startCalibrationBtn, { state: 'loading', icon: 'loader', text: 'Запуск...' });

                    const result = await apiPost(API.SETTINGS.CALIBRATION_START, {
                        preset_filename: this.currentPreset.filename
                    });

                    this.notify(INFO, 'Калибровка запущена', `Запущена калибровка для ${result.preset}`);

                    await this.loadWorkingCalibration();
                } catch (e) {
                    console.error('Start calibration failed:', e);
                    this.notify(ERROR, 'Ошибка калибровки', 'Не удалось запустить калибровку');
                } finally {
                    ButtonState.set(this.elements.startCalibrationBtn, { state: 'normal', icon: 'play', text: 'Начать калибровку' });
                }
            }), TIMING.DEBOUNCE_CALIBRATION
        );
    }

    async captureStandard(standard) {
        const key = `calibrate-${standard}`;
        if (this.disabledStandards.has(standard)) return;

        this.debouncer.debounce(key, () =>
            this.reqGuard.runExclusive(key, async () => {
                try {
                    this.disabledStandards.add(standard);

                    const btn = document.querySelector(`[data-standard="${standard}"]`);
                    ButtonState.set(btn, { state: 'loading', icon: 'upload', text: 'Снятие...' });
                    this.toggleStandardButtons(true);

                    this.notify(INFO, 'Снятие стандарта', `Снимается стандарт ${standard.toUpperCase()}...`);

                    const result = await apiPost(API.SETTINGS.CALIBRATION_ADD_STANDARD, { standard });

                    this.notify(SUCCESS, 'Стандарт снят', result.message);

                    this.resetCaptureState();
                    await this.loadWorkingCalibration();
                } catch (e) {
                    console.error('Capture standard failed:', e);
                    this.notify(ERROR, 'Ошибка калибровки', 'Не удалось снять стандарт калибровки');
                    this.resetCaptureState(standard);
                } finally {
                    this.toggleStandardButtons(false);
                }
            }), TIMING.DEBOUNCE_CALIBRATION
        );
    }

    toggleStandardButtons(disabled) {
        const buttons = this.elements.calibrationStandards?.querySelectorAll('.calibration-standard-btn');
        if (!buttons) return;
        buttons.forEach(btn => {
            if (disabled) {
                btn.dataset.prevDisabled = btn.disabled ? '1' : '0';
                btn.disabled = true;
            } else {
                if (btn.dataset.prevDisabled !== undefined) {
                    btn.disabled = btn.dataset.prevDisabled === '1';
                    delete btn.dataset.prevDisabled;
                }
            }
        });
    }

    async handleSaveCalibration() {
        const name = this.elements.calibrationNameInput.value.trim();
        if (!name) return;

        this.debouncer.debounce('save-calibration', () =>
            this.reqGuard.runExclusive('save-calibration', async () => {
                try {
                    ButtonState.set(this.elements.saveCalibrationBtn, { state: 'loading', icon: 'loader', text: 'Сохранение...' });

                    const result = await apiPost(API.SETTINGS.CALIBRATION_SAVE, { name });

                    this.notify(SUCCESS, 'Калибровка сохранена', result.message);

                    this.hideSteps();
                    this.elements.calibrationNameInput.value = '';

                    await this.loadWorkingCalibration();
                    await this.loadCalibrations();

                    if (this.onCalibrationSaved) {
                        await this.onCalibrationSaved();
                    }
                } catch (e) {
                    console.error('Save calibration failed:', e);
                    this.notify(ERROR, 'Ошибка калибровки', 'Не удалось сохранить калибровку');
                } finally {
                    ButtonState.set(this.elements.saveCalibrationBtn, { state: 'disabled', icon: 'save', text: 'Сохранить калибровку' });
                }
            }), TIMING.DEBOUNCE_CALIBRATION
        );
    }

    async handleSetCalibration() {
        this.debouncer.debounce('set-calibration', () =>
            this.reqGuard.runExclusive('set-calibration', async () => {
                const name = this.elements.calibrationDropdown.value;
                if (!name || !this.currentPreset) return;

                try {
                    ButtonState.set(this.elements.setCalibrationBtn, { state: 'loading', icon: 'loader', text: 'Применение...' });

                    const result = await apiPost(API.SETTINGS.CALIBRATION_SET, {
                        name,
                        preset_filename: this.currentPreset.filename
                    });

                    this.notify(SUCCESS, 'Калибровка применена', result.message);

                    if (this.onCalibrationSet) {
                        await this.onCalibrationSet();
                    }
                } catch (e) {
                    console.error('Set calibration failed:', e);
                    this.notify(ERROR, 'Ошибка калибровки', 'Не удалось применить калибровку');
                } finally {
                    ButtonState.set(this.elements.setCalibrationBtn, { state: 'normal', icon: 'check', text: 'Сделать активной' });
                }
            }), TIMING.DEBOUNCE_CALIBRATION
        );
    }

    async handleDeleteCalibration() {
        const name = this.elements.calibrationDropdown.value;
        if (!name || !this.currentPreset) {
            return;
        }

        if (!confirm(`Удалить калибровку «${name}»? Это действие необратимо.`)) {
            return;
        }

        this.debouncer.debounce('delete-calibration', () =>
            this.reqGuard.runExclusive('delete-calibration', async () => {
                try {
                    if (this.elements.deleteCalibrationBtn) {
                        ButtonState.set(this.elements.deleteCalibrationBtn, { state: 'loading', icon: 'loader', text: 'Удаление...' });
                    }

                    const url = buildUrl(API.SETTINGS.CALIBRATION_DELETE(name), {
                        preset_filename: this.currentPreset.filename
                    });
                    const result = await apiDelete(url);

                    this.notify(SUCCESS, 'Калибровка удалена', result.message);

                    await this.loadCalibrations();
                    await this.loadWorkingCalibration();

                    if (this.onCalibrationSet) {
                        await this.onCalibrationSet();
                    }
                } catch (e) {
                    console.error('Delete calibration failed:', e);
                    this.notify(ERROR, 'Ошибка калибровки', 'Не удалось удалить калибровку');
                } finally {
                    if (this.elements.deleteCalibrationBtn) {
                        ButtonState.set(this.elements.deleteCalibrationBtn, { state: 'normal', icon: 'trash-2', text: 'Удалить' });
                    }
                }
            }), TIMING.DEBOUNCE_CALIBRATION
        );
    }

    async handleClearCalibration() {
        if (!this.currentPreset || !this.currentCalibration) {
            return;
        }

        if (!confirm(`Сбросить текущую калибровку «${this.currentCalibration.calibration_name}»? Вы сможете выбрать её снова позже.`)) {
            return;
        }

        this.debouncer.debounce('clear-calibration', () =>
            this.reqGuard.runExclusive('clear-calibration', async () => {
                try {
                    if (this.elements.clearCalibrationBtn) {
                        ButtonState.set(this.elements.clearCalibrationBtn, { state: 'loading', icon: 'loader', text: 'Сброс...' });
                    }

                    const result = await apiDelete(API.SETTINGS.CALIBRATION_CLEAR_CURRENT);

                    this.notify(INFO, 'Калибровка сброшена', result.message);

                    this.currentCalibration = null;
                    if (this.elements.currentCalibration) {
                        this.elements.currentCalibration.textContent = 'Нет';
                    }

                    if (this.elements.calibrationDropdown) {
                        this.elements.calibrationDropdown.value = '';
                    }

                    await this.loadCalibrations();
                    await this.loadWorkingCalibration();

                    if (this.onCalibrationSet) {
                        await this.onCalibrationSet();
                    }
                } catch (e) {
                    console.error('Clear calibration failed:', e);
                    this.notify(ERROR, 'Ошибка калибровки', 'Не удалось сбросить калибровку');
                } finally {
                    if (this.elements.clearCalibrationBtn) {
                        ButtonState.set(this.elements.clearCalibrationBtn, { state: 'normal', icon: 'square', text: 'Сбросить' });
                    }
                }
            }), TIMING.DEBOUNCE_CALIBRATION
        );
    }

    updateStatus(status) {
        if (status.current_calibration) {
            this.currentCalibration = status.current_calibration;
            this.elements.currentCalibration.textContent = status.current_calibration.calibration_name;
        } else {
            this.currentCalibration = null;
            this.elements.currentCalibration.textContent = 'Нет';
        }

        if (this.elements.clearCalibrationBtn) {
            this.elements.clearCalibrationBtn.disabled = !this.currentCalibration;
        }
    }

    resetCaptureState(standard = null) {
        if (standard) this.disabledStandards.delete(standard);
        else this.disabledStandards.clear();

        if (this.workingCalibration) {
            this.renderStandardButtons(this.workingCalibration);
        }
    }

    reset() {
        this.workingCalibration = null;
        this.hideSteps();
        if (this.elements.calibrationNameInput) {
            this.elements.calibrationNameInput.value = '';
            this.elements.calibrationNameInput.disabled = true;
        }
        if (this.elements.saveCalibrationBtn) this.elements.saveCalibrationBtn.disabled = true;
        if (this.elements.progressText) this.elements.progressText.textContent = '0/0';
        if (this.elements.clearCalibrationBtn) this.elements.clearCalibrationBtn.disabled = true;
    }

    getWorkingCalibration() {
        return this.workingCalibration;
    }

    notify(type, title, message) {
        this.notifications?.show?.({ type, title, message });
    }
}
