<script setup lang="ts">
/**
 * Дашборд — стартовая страница. Audit C1/J3: KPI/баланс/активность/воронка
 * грузятся из GET /api/dashboard/summary; при ошибке — fallback на mock,
 * чтобы UI оставался работоспособным (dev / отсутствие backend).
 */
import { computed, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import ActivityChart from '../components/charts/ActivityChart.vue';
import FunnelChart from '../components/charts/FunnelChart.vue';
import DashboardPageHead from '../components/dashboard/DashboardPageHead.vue';
import DashboardKpiRow, { type Kpi } from '../components/dashboard/DashboardKpiRow.vue';
import DashboardBalance, { type Balance } from '../components/dashboard/DashboardBalance.vue';
import { getDashboardSummary, type DashboardRange, type DashboardSummary } from '../api/dashboard';
import { useAuthStore } from '../stores/auth';

const auth = useAuthStore();
const router = useRouter();
const range = ref<DashboardRange | 'custom'>('7d');

// Косяк 07: онбординг новичка. Показываем «с чего начать», когда сводка
// уже загружена и у клиента нет ни активных проектов, ни лидов за период.
const loaded = ref(false);
const activeProjectsCount = ref(0);
const leadsReceivedCount = ref(0);
const onboardingDismissed = ref(localStorage.getItem('dashboard.onboardingDismissed') === '1');
const showOnboarding = computed(
    () => loaded.value && !onboardingDismissed.value && activeProjectsCount.value === 0 && leadsReceivedCount.value === 0,
);
function dismissOnboarding(): void {
    onboardingDismissed.value = true;
    localStorage.setItem('dashboard.onboardingDismissed', '1');
}

// runwayMax — display-константа полосы (7 сегментов), не из API.
const RUNWAY_MAX = 7;

// Пустой стартовый стейт (БЕЗ фейк-данных): KPI/баланс/график = нули до ответа
// GET /api/dashboard/summary. При ошибке остаются нули + баннер fetchError —
// пользователь не видит выдуманных цифр (прежний mock-fallback показывал
// «247 лидов / 18.4% / 14 250₽» как настоящие — F5).
const EMPTY_KPIS: Kpi[] = [
    {
        label: 'Получено лидов',
        value: '0',
        delta: { dir: 'neutral', text: '' },
        sub: 'vs предыдущий период',
        hint: 'Сколько заявок вы получили за выбранный период.',
    },
    {
        label: 'Конверсия в оплату',
        value: '0',
        unit: '%',
        delta: { dir: 'neutral', text: '' },
        sub: 'vs предыдущий период',
        hint: 'Доля полученных заявок, по которым прошла оплата.',
    },
    {
        label: 'Активные проекты',
        value: '0',
        delta: { dir: 'neutral', text: '' },
        sub: 'лимит тарифа',
        hint: 'Проекты, которые сейчас собирают заявки.',
    },
];
const EMPTY_BALANCE: Balance = { amount: '0', runwayDays: 0, runwayMax: RUNWAY_MAX, runwayLeads: 0 };

const kpis = ref<Kpi[]>(EMPTY_KPIS);
const balance = ref<Balance>(EMPTY_BALANCE);
const activityPoints = ref<number[]>([0, 0, 0, 0, 0, 0, 0]);
const activityLabels = ref<string[]>(['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'сегодня']);
const activityMax = ref(60);
const funnelCounts = ref<Record<string, number> | undefined>(undefined);
// F5: средняя стоимость лида из API (avg_lead_cost_rub); null — нет rub-списаний.
const avgLeadCost = ref<number | null>(null);
const fetchError = ref(false);

// F5: сегодня/вчера для meta-строки — из последних точек активности
// (последняя точка = сегодня, предпоследняя = вчера; activity всегда 7 дней).
const leadsToday = computed(() => activityPoints.value[activityPoints.value.length - 1] ?? 0);
const leadsYesterday = computed(() => activityPoints.value[activityPoints.value.length - 2] ?? 0);

/** Форматирует число с пробелами-разделителями тысяч ('14250.00' → '14 250'). */
function formatRub(raw: string): string {
    const n = parseFloat(raw);
    if (!Number.isFinite(n)) return '0';
    const int = Math.round(n).toString();
    return int.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}

function applySummary(s: DashboardSummary): void {
    kpis.value = [
        {
            label: 'Получено лидов',
            value: String(s.leads_received.value),
            delta: { dir: s.leads_received.delta_dir, text: `${s.leads_received.delta_pct}%` },
            sub: 'vs предыдущий период',
            hint: 'Сколько заявок вы получили за выбранный период.',
        },
        {
            label: 'Конверсия в оплату',
            value: String(s.conversion.value),
            unit: '%',
            // «п.п.» (процентные пункты) вместо англ. «pp» — понятнее новичку.
            delta: { dir: s.conversion.delta_dir, text: `${s.conversion.delta_pp} п.п.` },
            sub: 'vs предыдущий период',
            hint: 'Доля полученных заявок, по которым прошла оплата.',
        },
        {
            label: 'Активные проекты',
            value: String(s.active_projects.active),
            // Лимита по числу проектов нет (ограничение только по балансу/лидам) —
            // показываем просто количество активных, без «/ N лимит тарифа».
            unit: '',
            delta: { dir: 'neutral', text: '' },
            sub: '',
            hint: 'Проекты, которые сейчас собирают заявки.',
        },
    ];
    balance.value = {
        amount: formatRub(s.balance.amount_rub),
        // F3: реальное число дней (полоса из RUNWAY_MAX сегментов заполняется
        // естественно `i <= runwayDays`; раньше cap до 7 врал в тексте «хватит на N дней»).
        runwayDays: s.balance.runway_days,
        runwayMax: RUNWAY_MAX,
        runwayLeads: s.balance.runway_leads,
    };
    activityPoints.value = s.activity.points;
    activityLabels.value = s.activity.labels;
    activityMax.value = s.activity.max;
    funnelCounts.value = s.funnel;
    avgLeadCost.value = s.avg_lead_cost_rub;
    activeProjectsCount.value = s.active_projects.active;
    leadsReceivedCount.value = s.leads_received.value;
    loaded.value = true;
}

async function load(): Promise<void> {
    const tenantId = auth.user?.tenant_id;
    if (!tenantId || range.value === 'custom') return;
    try {
        applySummary(await getDashboardSummary(tenantId, range.value as DashboardRange));
        fetchError.value = false;
    } catch {
        fetchError.value = true; // оставляем последнее значение / mock
    }
}

watch(range, load);
load();
</script>

<template>
    <v-container fluid class="dashboard pa-6">
        <DashboardPageHead
            v-model="range"
            :leads-today="leadsToday"
            :leads-yesterday="leadsYesterday"
            :avg-lead-cost-rub="avgLeadCost"
        />

        <!-- Косяк 07: онбординг новичка — «с чего начать» вместо пустых нулей без подсказок. -->
        <v-card
            v-if="showOnboarding"
            variant="tonal"
            color="primary"
            class="onboarding-card mt-4"
            data-testid="dashboard-onboarding"
        >
            <v-card-text>
                <div class="d-flex align-start justify-space-between ga-2">
                    <div>
                        <h2 class="text-h6 mb-1">Добро пожаловать в Лидерру!</h2>
                        <p class="text-medium-emphasis mb-2">
                            Чтобы пошли лиды — создайте первый проект и пополните баланс. Это пара минут.
                        </p>
                    </div>
                    <v-btn
                        icon="mdi-close"
                        size="small"
                        variant="text"
                        data-testid="onboarding-dismiss"
                        aria-label="Скрыть подсказку"
                        @click="dismissOnboarding"
                    />
                </div>
                <ol class="onboarding-steps">
                    <li>Создайте первый проект — короткие реквизиты попросим прямо в окне.</li>
                    <li>Пополните баланс — лиды списываются по факту.</li>
                    <li>Готово: Лидерра поставит проект в сбор, лиды пойдут автоматически.</li>
                </ol>
                <div class="mt-3 d-flex flex-wrap ga-2">
                    <v-btn
                        color="primary"
                        variant="flat"
                        data-testid="onboarding-create-project"
                        @click="router.push('/projects')"
                    >
                        Создать первый проект
                    </v-btn>
                    <v-btn
                        color="primary"
                        variant="outlined"
                        data-testid="onboarding-topup"
                        @click="router.push('/billing')"
                    >
                        Пополнить баланс
                    </v-btn>
                </div>
            </v-card-text>
        </v-card>

        <div v-show="!fetchError" class="ld-meta mt-2">
            <span class="ld-pulse" aria-hidden="true"></span>
            <span>Live · обновлено только что</span>
        </div>

        <v-row dense class="kpi-row mt-4">
            <DashboardKpiRow :kpis="kpis" />
            <DashboardBalance :balance="balance" />
        </v-row>

        <v-alert
            v-if="fetchError"
            type="warning"
            variant="tonal"
            density="compact"
            class="mt-3"
            data-testid="dashboard-fetch-error"
        >
            Не удалось обновить данные дашборда — показаны последние известные значения.
        </v-alert>

        <v-row class="charts-row mt-4">
            <v-col cols="12" md="7">
                <ActivityChart :points="activityPoints" :labels="activityLabels" :max="activityMax" />
            </v-col>
            <v-col cols="12" md="5">
                <FunnelChart :counts="funnelCounts" />
            </v-col>
        </v-row>
    </v-container>
</template>

<style scoped>
.dashboard {
    max-width: 1440px;
}

.ld-meta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: #66635c;
    letter-spacing: 0.02em;
}

.onboarding-steps {
    margin: 4px 0 0;
    padding-left: 20px;
    line-height: 1.7;
}
.onboarding-steps li {
    margin-bottom: 2px;
}
</style>
