<script setup lang="ts">
/**
 * AdminInvoicesView — SaaS-admin экран «Счета» (Этап 1 «оплата по счёту»).
 * Серверная пагинация/поиск/фильтр по статусу. Кнопка «Отметить оплаченным»
 * у выставленных счетов открывает диалог подтверждения → markInvoicePaid →
 * зачисление баланса + формирование Акта на бэкенде.
 */
import { ref, onMounted, watch } from 'vue';
import {
    listAdminInvoices,
    markInvoicePaid,
    type AdminInvoiceRow,
} from '../../api/admin';
import { extractErrorMessage } from '../../api/client';

const STATUS_LABELS: Record<string, string> = {
    draft: 'Черновик',
    issued: 'Выставлен',
    paid: 'Оплачен',
    overdue: 'Просрочен',
    cancelled: 'Отменён',
};
const STATUS_COLORS: Record<string, string> = {
    issued: 'info',
    paid: 'success',
    overdue: 'warning',
    cancelled: 'grey',
    draft: 'grey',
};

const STATUS_FILTERS = [
    { value: '', title: 'Все статусы' },
    { value: 'issued', title: 'Выставленные' },
    { value: 'paid', title: 'Оплаченные' },
    { value: 'overdue', title: 'Просроченные' },
    { value: 'cancelled', title: 'Отменённые' },
];

const rows = ref<AdminInvoiceRow[]>([]);
const loading = ref(true);
const loadError = ref<string | null>(null);

const page = ref(1);
const perPage = ref(25);
const total = ref(0);
const lastPage = ref(1);
const search = ref('');
const filterStatus = ref('');

const confirmOpen = ref(false);
const confirmRow = ref<AdminInvoiceRow | null>(null);
const marking = ref(false);
const snackbar = ref(false);
const snackMsg = ref('');

let searchTimer: ReturnType<typeof setTimeout> | undefined;

function statusLabel(s: string): string {
    return STATUS_LABELS[s] ?? s;
}
function statusColor(s: string): string {
    return STATUS_COLORS[s] ?? 'grey';
}
function formatDate(iso: string | null): string {
    return iso ? new Date(iso).toLocaleDateString('ru-RU', { timeZone: 'Europe/Moscow' }) : '—';
}
function formatAmount(v: string): string {
    return new Intl.NumberFormat('ru-RU', { minimumFractionDigits: 2 }).format(Number(v));
}

async function load(): Promise<void> {
    loading.value = true;
    loadError.value = null;
    try {
        const res = await listAdminInvoices({
            status: filterStatus.value || undefined,
            search: search.value || undefined,
            page: page.value,
            per_page: perPage.value,
        });
        rows.value = res.data;
        total.value = res.meta.total;
        lastPage.value = res.meta.last_page;
    } catch (e) {
        loadError.value = extractErrorMessage(e, 'Не удалось загрузить счета.');
    } finally {
        loading.value = false;
    }
}

function goPage(p: number): void {
    page.value = p;
    void load();
}

watch(search, () => {
    if (searchTimer) clearTimeout(searchTimer);
    searchTimer = setTimeout(() => {
        page.value = 1;
        void load();
    }, 400);
});

watch(filterStatus, () => {
    page.value = 1;
    void load();
});

function askMarkPaid(row: AdminInvoiceRow): void {
    confirmRow.value = row;
    confirmOpen.value = true;
}

async function doMarkPaid(): Promise<void> {
    if (confirmRow.value === null) return;
    marking.value = true;
    try {
        await markInvoicePaid(confirmRow.value.id);
        snackMsg.value = `Счёт ${confirmRow.value.invoice_number} отмечен оплаченным, баланс зачислен.`;
        snackbar.value = true;
        confirmOpen.value = false;
        confirmRow.value = null;
        await load();
    } catch (e) {
        snackMsg.value = extractErrorMessage(e, 'Не удалось отметить оплату.');
        snackbar.value = true;
    } finally {
        marking.value = false;
    }
}

onMounted(load);

defineExpose({ rows, page, perPage, total, search, filterStatus, goPage, load });
</script>

<template>
    <v-container class="invoices-admin" fluid>
        <div class="page-head mb-4">
            <h1 class="text-h5 page-title ma-0">Счета</h1>
        </div>

        <div class="filters mb-4">
            <v-text-field
                v-model="search"
                label="Поиск по номеру, клиенту, плательщику"
                density="comfortable"
                hide-details
                clearable
                prepend-inner-icon="mdi-magnify"
                style="max-width: 420px"
            />
            <v-select
                v-model="filterStatus"
                :items="STATUS_FILTERS"
                item-title="title"
                item-value="value"
                label="Статус"
                density="comfortable"
                hide-details
                style="max-width: 220px"
            />
        </div>

        <v-card variant="outlined">
            <div v-if="loading" class="py-10 d-flex justify-center">
                <v-progress-circular indeterminate color="primary" />
            </div>

            <v-alert v-else-if="loadError" type="error" variant="tonal" class="ma-4" role="alert">
                {{ loadError }}
            </v-alert>

            <div v-else-if="rows.length === 0" class="py-10 text-center text-medium-emphasis">
                Счетов не найдено.
            </div>

            <v-table v-else>
                <thead>
                    <tr>
                        <th>Дата</th>
                        <th>Номер</th>
                        <th>Клиент</th>
                        <th>Плательщик</th>
                        <th class="text-right">Сумма, ₽</th>
                        <th>Статус</th>
                        <th>Оплатить до</th>
                        <th class="text-right">Действие</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="r in rows" :key="r.id">
                        <td class="num">{{ formatDate(r.issued_at) }}</td>
                        <td class="num">{{ r.invoice_number }}</td>
                        <td>{{ r.tenant_name ?? '—' }}</td>
                        <td>{{ r.payer_name ?? '—' }}</td>
                        <td class="text-right num">{{ formatAmount(r.amount_total) }}</td>
                        <td><v-chip :color="statusColor(r.status)" size="small" variant="tonal">{{ statusLabel(r.status) }}</v-chip></td>
                        <td class="num">{{ formatDate(r.expires_at) }}</td>
                        <td class="text-right">
                            <v-btn
                                v-if="r.status === 'issued' || r.status === 'overdue'"
                                color="success"
                                size="small"
                                variant="flat"
                                :data-testid="`mark-paid-${r.id}`"
                                @click="askMarkPaid(r)"
                            >
                                Отметить оплаченным
                            </v-btn>
                        </td>
                    </tr>
                </tbody>
            </v-table>

            <div v-if="lastPage > 1" class="d-flex justify-center py-4">
                <v-pagination
                    :model-value="page"
                    :length="lastPage"
                    :total-visible="7"
                    @update:model-value="goPage"
                />
            </div>
        </v-card>

        <v-dialog v-model="confirmOpen" max-width="460">
            <v-card v-if="confirmRow">
                <v-card-title class="text-h6">Подтверждение оплаты</v-card-title>
                <v-card-text>
                    Отметить счёт <b>{{ confirmRow.invoice_number }}</b> на сумму
                    <b>{{ formatAmount(confirmRow.amount_total) }} ₽</b>
                    (клиент: {{ confirmRow.tenant_name ?? confirmRow.payer_name ?? '—' }}) как оплаченный?
                    Баланс клиента будет пополнен, сформируется Акт.
                </v-card-text>
                <v-card-actions>
                    <v-spacer />
                    <v-btn variant="text" :disabled="marking" @click="confirmOpen = false">Отмена</v-btn>
                    <v-btn color="success" variant="flat" :loading="marking" @click="doMarkPaid">Подтверждаю</v-btn>
                </v-card-actions>
            </v-card>
        </v-dialog>

        <v-snackbar v-model="snackbar" :timeout="5000" color="success">{{ snackMsg }}</v-snackbar>
    </v-container>
</template>

<style scoped>
.page-title {
    font-variation-settings: 'opsz' 24;
    letter-spacing: -0.015em;
}
.filters {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
}
.num {
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-feature-settings: 'tnum';
}
</style>
