<script setup lang="ts">
/**
 * Settings → Уведомления. Матрица 8 событий × 3 канала (inapp/push/email)
 * + sound_enabled. Соответствует schema.sql:699 users.notification_preferences.
 *
 * События (точно по schema-default):
 *   new_lead / reminder / low_balance / zero_balance /
 *   topup_success / invoice_paid / new_device_login / marketing.
 *
 * Каналы (точно по schema):
 *   inapp (bell-icon в UI) / push (web-push, Post-MVP) / email (Unisender Go).
 *
 * Push-канал на MVP пока не доставляется (требует ServiceWorker + VAPID), но
 * preferences записываются для будущей активации без миграции данных.
 */
import { computed, ref, watch } from 'vue';
import { useAuthStore } from '../../stores/auth';
import {
    type NotificationChannel,
    type NotificationEventKey,
    type NotificationPreferences,
    updateNotificationPreferences,
} from '../../api/auth';

interface NotifEvent {
    id: NotificationEventKey;
    label: string;
    description?: string;
}

const EVENTS: NotifEvent[] = [
    { id: 'new_lead', label: 'Новый лид', description: 'Поступил новый лид через webhook или manual-создание.' },
    { id: 'reminder', label: 'Напоминание', description: 'Срок касания клиента наступил.' },
    { id: 'low_balance', label: 'Низкий баланс', description: 'Осталось < 3 дней работы по текущим ценам.' },
    { id: 'zero_balance', label: 'Нулевой баланс', description: 'Лиды отклоняются — нет средств для оплаты.' },
    { id: 'topup_success', label: 'Пополнение успешно', description: 'Платёж зачислен на баланс.' },
    { id: 'invoice_paid', label: 'Счёт оплачен', description: 'Тарифный счёт списан.' },
    { id: 'new_device_login', label: 'Новое устройство', description: 'Вход с незнакомого устройства / IP.' },
    { id: 'marketing', label: 'Анонсы и промо', description: 'Новости платформы, скидки, новые функции.' },
];

interface ChannelKey {
    id: NotificationChannel;
    label: string;
    description: string;
}

const CHANNELS: ChannelKey[] = [
    { id: 'inapp', label: 'В приложении', description: 'Колокольчик в интерфейсе.' },
    { id: 'push', label: 'Push', description: 'Web-push в браузер (включится в Post-MVP).' },
    { id: 'email', label: 'Email', description: 'На адрес в профиле.' },
];

const auth = useAuthStore();

function buildPrefs(): NotificationPreferences {
    const userPrefs = auth.user?.notification_preferences ?? {};
    const next: NotificationPreferences = {};
    for (const e of EVENTS) {
        next[e.id] = {};
        for (const c of CHANNELS) {
            const stored = userPrefs[e.id]?.[c.id];
            next[e.id]![c.id] = typeof stored === 'boolean' ? stored : false;
        }
    }
    return next;
}

// Инициализация синхронно в setup() — иначе v-if="prefs[e.id]" блокирует
// рендер чекбоксов до onMounted, и тесты mount-then-find падают.
const prefs = ref<NotificationPreferences>(buildPrefs());
const soundEnabled = ref<boolean>(auth.user?.sound_enabled ?? true);
const saving = ref(false);
const saveSuccess = ref(false);
const saveError = ref(false);

// Snapshot оригинальных значений из auth.user — для определения dirty.
// Replacing с deep-clone чтобы JSON.stringify сравнение работало стабильно.
const originalPrefs = ref<NotificationPreferences>(buildPrefs());
const originalSound = ref<boolean>(auth.user?.sound_enabled ?? true);

const dirty = computed(
    () =>
        JSON.stringify(prefs.value) !== JSON.stringify(originalPrefs.value) ||
        soundEnabled.value !== originalSound.value,
);

function readFromUser(): void {
    prefs.value = buildPrefs();
    soundEnabled.value = auth.user?.sound_enabled ?? true;
    originalPrefs.value = buildPrefs();
    originalSound.value = auth.user?.sound_enabled ?? true;
}

watch(() => auth.user?.id, readFromUser);

async function save(): Promise<void> {
    if (saving.value) return;
    saving.value = true;
    saveSuccess.value = false;
    saveError.value = false;
    try {
        const updatedUser = await updateNotificationPreferences({
            prefs: prefs.value,
            sound_enabled: soundEnabled.value,
        });
        // Синхронизируем auth.user без повторного /me-вызова.
        auth.user = { ...auth.user!, ...updatedUser };
        // Обновляем snapshot — dirty снова false.
        originalPrefs.value = buildPrefs();
        originalSound.value = auth.user.sound_enabled ?? true;
        saveSuccess.value = true;
    } catch {
        saveError.value = true;
    } finally {
        saving.value = false;
    }
}

function reset(): void {
    readFromUser();
}

const canSave = computed(() => dirty.value && !saving.value && auth.isAuthenticated);
</script>

<template>
    <div class="tab-content">
        <h2 class="tab-title text-h6 mb-4">Уведомления</h2>

        <v-alert
            v-if="saveSuccess"
            type="success"
            variant="tonal"
            density="compact"
            class="mb-3"
            closable
            data-testid="notifications-save-success"
            @click:close="saveSuccess = false"
        >
            Настройки сохранены.
        </v-alert>
        <v-alert
            v-if="saveError"
            type="warning"
            variant="tonal"
            density="compact"
            class="mb-3"
            closable
            data-testid="notifications-save-error"
            @click:close="saveError = false"
        >
            Не удалось сохранить настройки. Попробуйте позже.
        </v-alert>

        <v-card variant="outlined" class="pa-4 mb-4">
            <h3 class="text-subtitle-2 mb-3">События × каналы</h3>
            <p class="text-body-2 text-medium-emphasis mb-3">
                Матрица 8 событий × 3 каналов (соответствует
                <code>users.notification_preferences</code> в БД). Push активируется в Post-MVP.
            </p>
            <div class="prefs-table">
                <div class="prefs-head">
                    <div class="prefs-cell event-col">Событие</div>
                    <div v-for="ch in CHANNELS" :key="ch.id" class="prefs-cell ch-col" :title="ch.description">
                        {{ ch.label }}
                    </div>
                </div>
                <div v-for="e in EVENTS" :key="e.id" class="prefs-row" :data-event="e.id">
                    <div class="prefs-cell event-col">
                        <div>{{ e.label }}</div>
                        <div v-if="e.description" class="event-desc">{{ e.description }}</div>
                    </div>
                    <div v-for="ch in CHANNELS" :key="ch.id" class="prefs-cell ch-col">
                        <v-checkbox
                            v-if="prefs[e.id]"
                            v-model="prefs[e.id]![ch.id]"
                            density="compact"
                            hide-details
                            color="primary"
                            :data-testid="`pref-${e.id}-${ch.id}`"
                        />
                    </div>
                </div>
            </div>
        </v-card>

        <v-card variant="outlined" class="pa-4 mb-4">
            <h3 class="text-subtitle-2 mb-3">Звуковые алерты</h3>
            <v-switch
                v-model="soundEnabled"
                color="primary"
                hide-details
                data-testid="sound-enabled-switch"
                label="Воспроизводить звук при новом in-app уведомлении"
            />
        </v-card>

        <div class="actions-row">
            <v-btn color="primary" :loading="saving" :disabled="!canSave" data-testid="save-btn" @click="save">
                Сохранить
            </v-btn>
            <v-btn variant="outlined" :disabled="!dirty || saving" data-testid="reset-btn" @click="reset">
                Отменить
            </v-btn>
        </div>
    </div>
</template>

<style scoped>
.tab-title {
    font-variation-settings: 'opsz' 18;
    letter-spacing: -0.005em;
}

.prefs-table {
    border: 1px solid #e8e3d6;
    border-radius: 8px;
    overflow: hidden;
}

.prefs-head,
.prefs-row {
    display: grid;
    grid-template-columns: 1fr 110px 110px 130px;
    align-items: center;
}

.prefs-head {
    background: #f6f3ec;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #66635c;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
}

.prefs-row {
    border-top: 1px solid #f0ede4;
}

.prefs-cell {
    padding: 10px 12px;
}

.event-col {
    color: #081319;
    font-size: 13px;
}

.event-desc {
    font-size: 11px;
    color: #66635c;
    margin-top: 2px;
}

.ch-col {
    text-align: center;
    display: flex;
    justify-content: center;
}

.actions-row {
    display: flex;
    gap: 12px;
    margin-top: 8px;
}
</style>
