import { describe, it, expect, vi, beforeEach } from 'vitest';
import { mount, flushPromises } from '@vue/test-utils';
import { createPinia, setActivePinia } from 'pinia';
import { createVuetify } from 'vuetify';
import BillingView from '../../resources/js/views/BillingView.vue';
import * as billingApi from '../../resources/js/api/billing';
import type { Wallet } from '../../resources/js/api/billing';

vi.mock('../../resources/js/api/billing');

const vuetify = createVuetify();

function makeWallet(): Wallet {
    return {
        balance_rub: '14250.00',
        affordable_leads: 28,
        current_tier: { no: 1, price_rub: '500.00', leads_left_in_tier: 100 },
        next_tier: { no: 2, price_rub: '450.00', leads_in_tier: 200 },
        delivered_in_month: 0,
        runway_days: 142,
        tiers_preview: [
            { tier_no: 1, price_rub: '500.00', leads_in_tier: 100 },
            { tier_no: 2, price_rub: '450.00', leads_in_tier: 200 },
        ],
        tariff: {
            code: 'pro',
            name: 'Про',
            features: ['webhook', 'kanban', 'api'],
        },
    };
}

describe('BillingView.vue', () => {
    beforeEach(() => {
        setActivePinia(createPinia());
        vi.mocked(billingApi.getWallet).mockResolvedValue(makeWallet());
    });

    const factory = () =>
        mount(BillingView, {
            global: {
                plugins: [vuetify, createPinia()],
                stubs: { TransactionsTable: true, InvoicesTable: true, ChargesTab: true, TopupDialog: true },
            },
        });

    it('монтируется с заголовком «Биллинг и тарифы»', async () => {
        const wrapper = factory();
        await flushPromises();
        expect(wrapper.find('h1').text()).toBe('Биллинг и тарифы');
    });

    it('загружает кошелёк и показывает баланс в шапке', async () => {
        const wrapper = factory();
        await flushPromises();
        expect(billingApi.getWallet).toHaveBeenCalled();
        const text = wrapper.text();
        expect(text).toMatch(/14\s+250\s*₽/);
    });

    it('не показывает чип «лидов запас» в шапке', async () => {
        const wrapper = factory();
        await flushPromises();
        expect(wrapper.text()).not.toContain('лидов запас');
    });

    it('показывает «Запас» в BalanceCard вместо карточки «Тариф»', async () => {
        // tenant-store в тесте не замокан → requiredLeadsPerDay = 0 → нет активных проектов.
        // B1-2 (25.06): было «∞», теперь «—» + «нет активных проектов» (как на дашборде).
        const wrapper = factory();
        await flushPromises();
        const text = wrapper.text();
        expect(text).toContain('Запас');
        expect(text).toContain('нет активных проектов');
        expect(text).not.toContain('∞');
        expect(text).not.toContain('Тариф не выбран');
        expect(text).not.toContain('по тарифу');
    });

    it('показывает error-alert при сбое загрузки кошелька', async () => {
        vi.mocked(billingApi.getWallet).mockRejectedValue(new Error('network'));
        const wrapper = factory();
        await flushPromises();
        expect(wrapper.text()).toContain('Не удалось загрузить');
    });

    it('кнопка «Повторить» перезагружает кошелёк после ошибки', async () => {
        vi.mocked(billingApi.getWallet).mockReset();
        vi.mocked(billingApi.getWallet).mockRejectedValueOnce(new Error('network')).mockResolvedValueOnce(makeWallet());
        const wrapper = factory();
        await flushPromises();
        expect(wrapper.text()).toContain('Не удалось загрузить');

        const retry = wrapper.findAll('button').find((b) => b.text().includes('Повторить'));
        expect(retry).toBeDefined();
        await retry!.trigger('click');
        await flushPromises();

        expect(billingApi.getWallet).toHaveBeenCalledTimes(2);
        expect(wrapper.text()).toMatch(/14\s+250\s*₽/);
    });

    it('содержит табы Обзор / Списания', async () => {
        const wrapper = factory();
        await flushPromises();
        const text = wrapper.text();
        expect(text).toContain('Обзор');
        expect(text).toContain('Списания');
    });

    it('кнопка «Пополнить баланс» открывает TopupDialog', async () => {
        const wrapper = factory();
        await flushPromises();
        const btn = wrapper.findAll('button').find((b) => b.text().includes('Пополнить баланс'));
        expect(btn).toBeDefined();
        await btn!.trigger('click');
        expect((wrapper.vm as unknown as { topupOpen: boolean }).topupOpen).toBe(true);
    });

    it('не показывает pending-баннер (E4 — mock убран)', async () => {
        const wrapper = factory();
        await flushPromises();
        expect(wrapper.text()).not.toContain('в обработке');
    });

    it('рендерит TierPricesPanel между BalanceCard и TransactionsTable', async () => {
        const wrapper = factory();
        await flushPromises();
        expect(wrapper.text()).toContain('Цены за лид');
    });
});
