<script setup lang="ts">
import { ref, onMounted } from 'vue';
import axios from 'axios';

interface ReconcileRow {
    started_at: string;
    finished_at: string | null;
    window_start: string;
    window_end: string;
    status: string;
    total_csv_rows: number;
    matched_count: number;
    recovered_count: number;
    drift_ratio: number;
}

interface Health {
    last_run_at: string | null;
    last_status: string | null;
    drift_ratio: number | null;
    webhook_state: string;
}

const health = ref<Health | null>(null);
const history = ref<ReconcileRow[]>([]);
const loading = ref(false);
const reconciling = ref(false);
const error = ref<string | null>(null);

// --- Plan 4 Task 1: глобальный режим экспорта проектов (online|batch) ---

type ExportMode = 'online' | 'batch';
const exportMode = ref<ExportMode>('batch');
const exportModeError = ref<string | null>(null);
const exportModeSaving = ref(false);

async function loadExportMode(): Promise<void> {
    try {
        const { data } = await axios.get('/api/admin/supplier-integration/export-mode');
        if (data?.mode === 'online' || data?.mode === 'batch') {
            exportMode.value = data.mode;
        }
    } catch {
        exportModeError.value = 'Не удалось загрузить режим экспорта.';
    }
}

async function setExportMode(mode: ExportMode): Promise<void> {
    if (exportMode.value === mode) return;
    exportModeSaving.value = true;
    exportModeError.value = null;
    try {
        const { data } = await axios.post('/api/admin/supplier-integration/export-mode', { mode });
        exportMode.value = data?.mode === 'online' ? 'online' : 'batch';
    } catch {
        exportModeError.value = 'Не удалось сохранить режим экспорта.';
    } finally {
        exportModeSaving.value = false;
    }
}

// --- Тумблер «Разблокировка смены источника» (флаг routing_match_by_snapshot) ---

const sourceEditEnabled = ref(false);
const sourceEditError = ref<string | null>(null);
const sourceEditSaving = ref(false);
const sourceEditConfirmOpen = ref(false);
const pendingSourceEditValue = ref(false);
// VSwitch флипает внутреннее состояние по клику; бамп ключа ре-маунтит тумблер,
// чтобы он вернулся к фактическому sourceEditEnabled после отмены/ошибки.
const sourceEditSwitchKey = ref(0);

async function loadSourceEditFlag(): Promise<void> {
    try {
        const { data } = await axios.get('/api/admin/supplier-integration/source-edit-flag');
        sourceEditEnabled.value = data?.enabled === true;
    } catch {
        sourceEditError.value = 'Не удалось загрузить переключатель.';
    }
}

// Тумблер привязан к sourceEditEnabled один-в-один; запрос смены открывает
// подтверждение, фактическое значение меняется только после «Подтвердить».
function onSourceEditToggleRequest(val: boolean | null): void {
    pendingSourceEditValue.value = val === true;
    sourceEditConfirmOpen.value = true;
}

function cancelSourceEditToggle(): void {
    sourceEditConfirmOpen.value = false;
    sourceEditSwitchKey.value++; // вернуть тумблер к фактическому состоянию
}

async function confirmSourceEditToggle(): Promise<void> {
    sourceEditConfirmOpen.value = false;
    sourceEditSaving.value = true;
    sourceEditError.value = null;
    try {
        const { data } = await axios.post('/api/admin/supplier-integration/source-edit-flag', {
            enabled: pendingSourceEditValue.value,
        });
        sourceEditEnabled.value = data?.enabled === true;
    } catch {
        sourceEditError.value = 'Не удалось сохранить переключатель.';
    } finally {
        sourceEditSaving.value = false;
        sourceEditSwitchKey.value++; // синхронизировать тумблер с фактом (вкл. при ошибке)
    }
}

async function load(): Promise<void> {
    loading.value = true;
    error.value = null;
    try {
        const { data } = await axios.get('/api/admin/supplier-integration');
        health.value = data.health;
        history.value = data.history;
    } catch {
        error.value = 'Не удалось загрузить состояние канала.';
    } finally {
        loading.value = false;
    }
}

async function reconcileNow(): Promise<void> {
    reconciling.value = true;
    try {
        await axios.post('/api/admin/supplier-integration/reconcile');
        // Сверка асинхронная (queued job) — ждём ~4с и перезагружаем здоровье канала.
        setTimeout(() => void load(), 4000);
    } finally {
        reconciling.value = false;
    }
}

function statusColor(status: string | null): string {
    if (status === 'ok') return 'success';
    if (status === 'drift_alert') return 'warning';
    if (status === 'failed') return 'error';
    return 'grey';
}

// --- Эпик 5: история вечерних заливок проектов поставщику (supplier_sync_runs) ---

interface SyncRun {
    started_at: string;
    finished_at: string | null;
    groups_total: number;
    synced_ok: number;
    manual_queued: number;
    deferred: number;
    failed: number;
    status: string;
}

const syncRuns = ref<SyncRun[]>([]);
const syncRunsError = ref<string | null>(null);

async function loadSyncRuns(): Promise<void> {
    try {
        const { data } = await axios.get('/api/admin/supplier-integration/sync-runs');
        syncRuns.value = Array.isArray(data?.runs) ? data.runs : [];
    } catch {
        syncRunsError.value = 'Не удалось загрузить историю заливок.';
    }
}

function runStatusColor(status: string): string {
    if (status === 'ok') return 'success';
    if (status === 'partial') return 'warning';
    if (status === 'failed' || status === 'aborted') return 'error';
    return 'grey';
}

function runStatusLabel(status: string): string {
    if (status === 'ok') return 'Всё ровно';
    if (status === 'partial') return 'Частично';
    if (status === 'failed') return 'Сбой';
    if (status === 'aborted') return 'Прервано';
    return status;
}

// --- Ручная очередь (ярус 3 резерва канала миграции проектов) ---

interface ManualQueueRow {
    id: number;
    project_id: number;
    platform: string;
    operation: string;
    external_id: string | null;
    payload_snapshot: Record<string, unknown>;
    failure_reason: string;
    created_at: string;
}

const manualQueue = ref<ManualQueueRow[]>([]);
const manualQueueError = ref<string | null>(null);
const resolvingId = ref<number | null>(null);

async function loadManualQueue(): Promise<void> {
    try {
        const { data } = await axios.get('/api/admin/supplier-integration/manual-queue');
        manualQueue.value = Array.isArray(data?.queue) ? data.queue : [];
    } catch {
        manualQueueError.value = 'Не удалось загрузить очередь.';
    }
}

// UI-аудит: window.confirm/alert → v-dialog/v-snackbar.
const confirmResolveId = ref<number | null>(null);
const resolveToastOpen = ref(false);
const resolveToastText = ref('');
const resolveToastColor = ref<'success' | 'error'>('success');

function askResolve(id: number): void {
    confirmResolveId.value = id;
}

async function doResolve(): Promise<void> {
    const id = confirmResolveId.value;
    confirmResolveId.value = null;
    if (id === null) return;
    resolvingId.value = id;
    try {
        await axios.post(`/api/admin/supplier-integration/manual-queue/${id}/resolve`);
        await loadManualQueue();
        resolveToastColor.value = 'success';
        resolveToastText.value = 'Запись закрыта.';
        resolveToastOpen.value = true;
    } catch (e: unknown) {
        const err = e as { response?: { data?: { message?: string } } };
        resolveToastColor.value = 'error';
        resolveToastText.value = err?.response?.data?.message ?? 'Не удалось закрыть запись.';
        resolveToastOpen.value = true;
    } finally {
        resolvingId.value = null;
    }
}

function formatDate(s: string): string {
    return new Date(s).toLocaleString('ru-RU');
}

onMounted(() => {
    void load();
    void loadManualQueue();
    void loadExportMode();
    void loadSourceEditFlag();
    void loadSyncRuns();
});
</script>

<template>
    <div class="pa-6">
        <h1 class="text-h5 mb-4">Интеграция с поставщиком</h1>

        <v-card class="mb-4">
            <v-card-title>Режим экспорта проектов</v-card-title>
            <v-card-text>
                <v-alert v-if="exportModeError" type="error" density="compact" class="mb-3">
                    {{ exportModeError }}
                </v-alert>
                <div data-testid="export-mode-toggle">
                    <v-btn-toggle
                        :model-value="exportMode"
                        mandatory
                        color="primary"
                        density="comfortable"
                        :disabled="exportModeSaving"
                    >
                        <v-btn data-testid="export-mode-online" value="online" @click="setExportMode('online')">
                            Онлайн
                        </v-btn>
                        <v-btn data-testid="export-mode-batch" value="batch" @click="setExportMode('batch')">
                            Пакетный
                        </v-btn>
                    </v-btn-toggle>
                </div>
                <p class="text-caption text-medium-emphasis mt-3 mb-0">
                    Онлайн — изменения проекта переносятся к поставщику сразу. Пакетный — ночной синк в 18:00
                    (SyncSupplierProjectsJob).
                </p>
            </v-card-text>
        </v-card>

        <v-card class="mb-4" data-testid="source-edit-flag-card">
            <v-card-title>Разблокировка смены источника</v-card-title>
            <v-card-text>
                <v-alert v-if="sourceEditError" type="error" density="compact" class="mb-3">
                    {{ sourceEditError }}
                </v-alert>
                <v-switch
                    :key="sourceEditSwitchKey"
                    :model-value="sourceEditEnabled"
                    :loading="sourceEditSaving"
                    :disabled="sourceEditSaving"
                    color="primary"
                    hide-details
                    inset
                    data-testid="source-edit-flag-switch"
                    :label="sourceEditEnabled ? 'Включена' : 'Выключена'"
                    @update:model-value="onSourceEditToggleRequest"
                />
                <p class="text-caption text-medium-emphasis mt-1 mb-0">
                    ВКЛ — клиенты могут менять источник проекта без потери лидов (маршрутизация по слепку).
                    ВЫКЛ — смена источника заблокирована. Откат безопасен в любой момент.
                </p>
            </v-card-text>
        </v-card>

        <v-dialog v-model="sourceEditConfirmOpen" max-width="480" data-testid="source-edit-confirm">
            <v-card>
                <v-card-title>
                    {{ pendingSourceEditValue ? 'Включить' : 'Выключить' }} разблокировку смены источника?
                </v-card-title>
                <v-card-text>
                    <template v-if="pendingSourceEditValue">
                        Клиенты смогут менять источник проекта без потери лидов (матч по слепку).
                        Рекомендуется сутки понаблюдать по «Вечерней заливке», что лиды доезжают.
                    </template>
                    <template v-else>
                        Вернётся прежнее поведение: смена источника заблокирована. Откат безопасен.
                    </template>
                </v-card-text>
                <v-card-actions>
                    <v-spacer />
                    <v-btn variant="text" data-testid="source-edit-confirm-cancel" @click="cancelSourceEditToggle">
                        Отмена
                    </v-btn>
                    <v-btn
                        color="primary"
                        variant="flat"
                        :loading="sourceEditSaving"
                        data-testid="source-edit-confirm-apply"
                        @click="confirmSourceEditToggle"
                    >
                        Подтвердить
                    </v-btn>
                </v-card-actions>
            </v-card>
        </v-dialog>

        <v-card class="mb-4" data-testid="sync-runs-card">
            <v-card-title>Вечерняя заливка проектов поставщику</v-card-title>
            <v-card-text>
                <p class="text-caption text-medium-emphasis mb-3">
                    История запусков синхронизации проектов у поставщика (18:05 МСК). Сверяйте,
                    что заливка прошла ровно — от этого зависят заказанные на завтра лиды.
                </p>
                <v-alert v-if="syncRunsError" type="error" density="compact" class="mb-3">
                    {{ syncRunsError }}
                </v-alert>
                <v-table v-if="syncRuns.length > 0" density="comfortable" data-testid="sync-runs-table">
                    <thead>
                        <tr>
                            <th>Когда</th>
                            <th>Статус</th>
                            <th class="text-right">Групп</th>
                            <th class="text-right">Готово</th>
                            <th class="text-right">В ручную</th>
                            <th class="text-right">Ошибок</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="(run, i) in syncRuns" :key="i" data-testid="sync-run-row">
                            <td>{{ run.finished_at ? formatDate(run.finished_at) : formatDate(run.started_at) }}</td>
                            <td>
                                <v-chip :color="runStatusColor(run.status)" size="small">
                                    {{ runStatusLabel(run.status) }}
                                </v-chip>
                            </td>
                            <td class="text-right">{{ run.groups_total }}</td>
                            <td class="text-right">{{ run.synced_ok }}</td>
                            <td class="text-right">
                                <span :class="run.manual_queued > 0 ? 'text-warning font-weight-bold' : ''">
                                    {{ run.manual_queued }}
                                </span>
                            </td>
                            <td class="text-right">
                                <span :class="run.failed > 0 ? 'text-error font-weight-bold' : ''">
                                    {{ run.failed }}
                                </span>
                            </td>
                        </tr>
                    </tbody>
                </v-table>
                <div v-else class="text-medium-emphasis">Заливок пока не было.</div>
            </v-card-text>
        </v-card>

        <v-card class="mb-4">
            <v-card-title>Здоровье резервного канала</v-card-title>
            <v-card-text>
                <v-alert v-if="error" type="error" density="compact" class="mb-4">
                    {{ error }}
                </v-alert>
                <template v-if="health">
                    <div class="mb-2">
                        Webhook:
                        <v-chip :color="health.webhook_state === 'live' ? 'success' : 'error'" size="small">
                            {{ health.webhook_state }}
                        </v-chip>
                    </div>
                    <div class="mb-2">
                        Последняя сверка:
                        <v-chip :color="statusColor(health.last_status)" size="small">
                            {{ health.last_status ?? '—' }}
                        </v-chip>
                        <span class="ml-2">{{ health.last_run_at ?? '—' }}</span>
                    </div>
                    <div class="mb-4">
                        Расхождение (drift):
                        {{ health.drift_ratio !== null ? (health.drift_ratio * 100).toFixed(2) + ' %' : '—' }}
                    </div>
                </template>
                <div v-else-if="loading" class="mb-4 text-medium-emphasis">Загрузка…</div>
                <v-btn data-test="reconcile-now" color="primary" :loading="reconciling" @click="reconcileNow">
                    Сверить сейчас
                </v-btn>
            </v-card-text>
        </v-card>

        <v-card>
            <v-card-title>История сверок</v-card-title>
            <v-table>
                <thead>
                    <tr>
                        <th>Начало</th>
                        <th>Статус</th>
                        <th>Строк CSV</th>
                        <th>Совпало</th>
                        <th>Подобрано</th>
                        <th>Drift</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="row in history" :key="row.started_at">
                        <td>{{ row.started_at }}</td>
                        <td>
                            <v-chip :color="statusColor(row.status)" size="x-small">{{ row.status }}</v-chip>
                        </td>
                        <td>{{ row.total_csv_rows }}</td>
                        <td>{{ row.matched_count }}</td>
                        <td>{{ row.recovered_count }}</td>
                        <td>{{ (row.drift_ratio * 100).toFixed(2) }} %</td>
                    </tr>
                </tbody>
            </v-table>
        </v-card>

        <v-card class="mt-4">
            <v-card-title>
                Ручная очередь
                <v-chip v-if="manualQueue.length" color="warning" class="ml-2" size="small">
                    {{ manualQueue.length }}
                </v-chip>
            </v-card-title>
            <v-card-text>
                <v-alert v-if="manualQueueError" type="error" density="compact">
                    {{ manualQueueError }}
                </v-alert>
                <p v-else-if="!manualQueue.length" class="text-medium-emphasis">
                    Очередь пуста — авто-фейловер не понадобился.
                </p>
                <v-table v-else density="compact">
                    <thead>
                        <tr>
                            <th>Project</th>
                            <th>Платформа</th>
                            <th>Операция</th>
                            <th>Параметры</th>
                            <th>Причина</th>
                            <th>Создано</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="row in manualQueue" :key="row.id">
                            <td>#{{ row.project_id }}</td>
                            <td>{{ row.platform }}</td>
                            <td>{{ row.operation }}</td>
                            <td>
                                <code>{{ row.payload_snapshot.unique_key }}</code>
                                · limit {{ row.payload_snapshot.limit ?? '—' }}
                            </td>
                            <td>{{ row.failure_reason }}</td>
                            <td>{{ formatDate(row.created_at) }}</td>
                            <td>
                                <v-btn
                                    size="small"
                                    color="primary"
                                    :data-testid="`resolve-${row.id}`"
                                    :loading="resolvingId === row.id"
                                    @click="askResolve(row.id)"
                                >
                                    Отметить выполнено
                                </v-btn>
                            </td>
                        </tr>
                    </tbody>
                </v-table>
            </v-card-text>
        </v-card>

        <v-dialog :model-value="confirmResolveId !== null" max-width="420" @update:model-value="confirmResolveId = null">
            <v-card class="pa-2">
                <v-card-title class="text-subtitle-1">Закрыть запись очереди?</v-card-title>
                <v-card-text>Подтверждаете, что внесли изменения в crm.bp-gr.ru?</v-card-text>
                <v-card-actions class="px-4 pb-3">
                    <v-spacer />
                    <v-btn variant="text" @click="confirmResolveId = null">Отмена</v-btn>
                    <v-btn color="primary" variant="flat" @click="doResolve">Подтверждаю</v-btn>
                </v-card-actions>
            </v-card>
        </v-dialog>

        <v-snackbar v-model="resolveToastOpen" :timeout="3500" :color="resolveToastColor" location="bottom right">
            {{ resolveToastText }}
        </v-snackbar>
    </div>
</template>
