<script setup lang="ts">
/**
 * Диалог создания новой сделки. Используется в DealsView и KanbanView.
 *
 * Submit-flow:
 *   1. Validate (≥10 digits phone, required fields).
 *   2. Если `tenantId` передан — POST /api/deals → backend возвращает deal с
 *      реальным id из БД. На fail (network / 500) — fallback на local-only
 *      (sync вид сохраняется, при reload потеряется — отображаем warning).
 *   3. Если `tenantId` не передан — чистый local-mode (legacy).
 *   4. emit('created', deal) → parent пушит в свой reactive-state.
 */
import * as dealsApi from '../../api/deals';
import { extractErrorMessage } from '../../api/client';
import { ref, watch } from 'vue';
import { LEAD_STATUSES } from '../../composables/leadStatuses';
import { type MockDeal, type MockManager } from '../../composables/mockDeals';

/**
 * Списки проектов и менеджеров грузятся с backend через GET /api/projects,
 * /api/managers при открытии диалога (если передан tenantId). На fail —
 * списки пустые + degradation-alert (lookupsFailed), создание блокируется
 * до повторной успешной загрузки.
 */
const projectOptions = ref<string[]>([]);
const managerOptions = ref<MockManager[]>([]);
// Map name → backend-id, нужен только когда manager_id отправляется на backend.
const managerIdByName = ref<Map<string, number>>(new Map());

async function loadLookups(tenantId: number) {
    try {
        const [projects, managers] = await Promise.all([
            dealsApi.listProjects(tenantId),
            dealsApi.listManagers(tenantId),
        ]);
        if (projects.length > 0) {
            projectOptions.value = projects.map((p) => p.name);
        }
        if (managers.length > 0) {
            managerOptions.value = managers.map((m) => ({ initials: m.initials, name: m.name }));
            const map = new Map<string, number>();
            managers.forEach((m) => map.set(m.name, m.id));
            managerIdByName.value = map;
        }
    } catch {
        // Audit C6: фиксируем провал — UI покажет degradation-alert.
        lookupsFailed.value = true;
    }
}

// Vue 3.5 defineModel() — заменяет props.modelValue + emit('update:modelValue').
// Sprint 2 Phase B / O-stack-04. Снижение boilerplate: 5 строк → 1.
const dialogOpen = defineModel<boolean>({ required: true });

const props = defineProps<{
    /** Опциональный preset статуса (KanbanView передаёт slug колонки куда дропают). */
    presetStatus?: MockDeal['statusSlug'];
    /**
     * Если передан — submit делает POST /api/deals. Если нет — чистый local-mode
     * (для тестов и legacy). На prod — всегда передаётся из родителя через
     * `auth.user.tenant_id`.
     */
    tenantId?: number;
}>();

const emit = defineEmits<{
    (e: 'created', deal: MockDeal): void;
}>();

const name = ref('');
const phone = ref('');
const project = ref<string | null>(null);
const manager = ref<MockManager | null>(null);
const cost = ref<number>(0);
const statusSlug = ref<MockDeal['statusSlug']>('new');

const errors = ref<Record<string, string>>({});
const submitError = ref<string | null>(null);
const busy = ref(false);

// Audit C6: loadLookups упал → показываем degradation-alert (списки пусты).
const lookupsFailed = ref(false);

// Регенерируем ID на каждое создание для local-mode. На API — backend SERIAL.
function nextId(): number {
    return Math.floor(Date.now() / 1000) + Math.floor(Math.random() * 1000);
}

function reset() {
    name.value = '';
    phone.value = '';
    project.value = null;
    manager.value = null;
    cost.value = 0;
    statusSlug.value = props.presetStatus ?? 'new';
    errors.value = {};
    submitError.value = null;
    busy.value = false;
    lookupsFailed.value = false;
}

watch(
    dialogOpen,
    (open) => {
        if (open) {
            reset();
            // Подгружаем lookups при открытии (дешевле грузить on-demand чем
            // на mount — диалог не открывается часто).
            if (props.tenantId) {
                loadLookups(props.tenantId);
            }
        }
    },
    { immediate: true },
);

function validate(): boolean {
    const e: Record<string, string> = {};
    if (!name.value.trim()) e.name = 'Имя обязательно.';
    if (!phone.value.trim()) e.phone = 'Телефон обязателен.';
    else if (phone.value.replace(/\D/g, '').length < 10) e.phone = 'Минимум 10 цифр.';
    if (!project.value) e.project = 'Выберите проект.';
    if (!manager.value) e.manager = 'Выберите менеджера.';
    if (cost.value < 0) e.cost = 'Стоимость не может быть отрицательной.';
    errors.value = e;
    return Object.keys(e).length === 0;
}

async function submit() {
    if (!validate()) return;
    submitError.value = null;
    busy.value = true;
    try {
        let dealId = nextId();
        // Backend create если tenantId передан. На fail — local-only fallback
        // (UI не блокируется при network-down, но warning показываем).
        if (props.tenantId) {
            try {
                // Manager mapping name → id (если backend lookup сработал).
                const managerId = manager.value ? managerIdByName.value.get(manager.value.name) : undefined;
                const created = await dealsApi.createDeal({
                    tenant_id: props.tenantId,
                    project_name: project.value!,
                    phone: phone.value.trim(),
                    contact_name: name.value.trim(),
                    status: statusSlug.value,
                    manager_id: managerId,
                });
                dealId = created.id;
            } catch (err) {
                submitError.value = extractErrorMessage(
                    err,
                    'Не удалось сохранить на сервере. Сделка добавлена локально.',
                );
                // Не делаем return — продолжаем с local-id для UI consistency.
            }
        }

        const deal: MockDeal = {
            id: dealId,
            name: name.value.trim(),
            phone: phone.value.trim(),
            statusSlug: statusSlug.value,
            project: project.value!,
            manager: { ...manager.value! },
            cost: cost.value,
            receivedMinutesAgo: 0,
        };
        emit('created', deal);
        // На submitError — оставляем dialog открытым с warning, иначе закрываем.
        if (submitError.value === null) {
            dialogOpen.value = false;
        }
    } finally {
        busy.value = false;
    }
}

defineExpose({ lookupsFailed, projectOptions, managerOptions });

function close() {
    dialogOpen.value = false;
}
</script>

<template>
    <v-dialog v-model="dialogOpen" :max-width="560" data-testid="new-deal-dialog">
        <v-card>
            <v-card-title>Новая сделка</v-card-title>
            <v-card-text>
                <v-alert
                    v-if="submitError"
                    type="warning"
                    variant="tonal"
                    density="compact"
                    class="mb-3"
                    data-testid="submit-error-alert"
                >
                    {{ submitError }}
                </v-alert>
                <v-alert
                    v-if="lookupsFailed"
                    type="warning"
                    variant="tonal"
                    density="compact"
                    class="mb-3"
                    data-testid="lookups-error-alert"
                >
                    Не удалось загрузить списки проектов и менеджеров — попробуйте позже.
                </v-alert>
                <v-row dense>
                    <v-col cols="12" md="6">
                        <v-text-field
                            v-model="name"
                            label="Имя клиента"
                            variant="outlined"
                            density="comfortable"
                            autofocus
                            :error-messages="errors.name ? [errors.name] : []"
                            data-testid="field-name"
                        />
                    </v-col>
                    <v-col cols="12" md="6">
                        <v-text-field
                            v-model="phone"
                            label="Телефон"
                            placeholder="+7 (___) ___-__-__"
                            variant="outlined"
                            density="comfortable"
                            inputmode="tel"
                            :error-messages="errors.phone ? [errors.phone] : []"
                            data-testid="field-phone"
                        />
                    </v-col>
                    <v-col cols="12" md="6">
                        <v-select
                            v-model="project"
                            :items="projectOptions"
                            label="Проект"
                            variant="outlined"
                            density="comfortable"
                            :error-messages="errors.project ? [errors.project] : []"
                            data-testid="field-project"
                        />
                    </v-col>
                    <v-col cols="12" md="6">
                        <v-select
                            v-model="manager"
                            :items="managerOptions"
                            item-title="name"
                            return-object
                            label="Менеджер"
                            variant="outlined"
                            density="comfortable"
                            :error-messages="errors.manager ? [errors.manager] : []"
                            data-testid="field-manager"
                        />
                    </v-col>
                    <v-col cols="12" md="6">
                        <v-text-field
                            v-model.number="cost"
                            label="Стоимость лида, ₽"
                            variant="outlined"
                            density="comfortable"
                            type="number"
                            min="0"
                            :error-messages="errors.cost ? [errors.cost] : []"
                            data-testid="field-cost"
                        />
                    </v-col>
                    <v-col cols="12" md="6">
                        <v-select
                            v-model="statusSlug"
                            :items="LEAD_STATUSES.map((s) => ({ value: s.slug, title: s.nameRu }))"
                            label="Статус"
                            variant="outlined"
                            density="comfortable"
                            data-testid="field-status"
                        />
                    </v-col>
                </v-row>
            </v-card-text>
            <v-card-actions>
                <v-spacer />
                <v-btn variant="text" :disabled="busy" data-testid="cancel-btn" @click="close">Отмена</v-btn>
                <v-btn color="primary" :loading="busy" data-testid="submit-btn" @click="submit">Создать</v-btn>
            </v-card-actions>
        </v-card>
    </v-dialog>
</template>
