import { describe, it, expect, vi, beforeEach } from 'vitest';
import { mount, flushPromises } from '@vue/test-utils';
import { createVuetify } from 'vuetify';
import { createRouter, createMemoryHistory } from 'vue-router';
import { createPinia, setActivePinia } from 'pinia';
import AdminTenantsView from '../../resources/js/views/admin/AdminTenantsView.vue';
import { mapApiAdminTenant } from '../../resources/js/composables/adminTenantsMapper';
import type { AdminTenant as ApiAdminTenant } from '../../resources/js/api/admin';

vi.mock('../../resources/js/api/admin', async (importOriginal) => {
    const orig = await importOriginal<typeof import('../../resources/js/api/admin')>();
    return {
        ...orig,
        listAdminTenants: vi.fn(),
        listAdminTariffPlans: vi.fn().mockResolvedValue([]),
    };
});

const adminApi = await import('../../resources/js/api/admin');

beforeEach(() => {
    vi.clearAllMocks();
    setActivePinia(createPinia());
});

function makeApiTenant(overrides: Partial<ApiAdminTenant> = {}): ApiAdminTenant {
    return {
        id: 1,
        subdomain: 'test',
        organization_name: 'Test ООО',
        contact_email: 'admin@test.io',
        status: 'active',
        balance_rub: '1000.00',
        balance_leads: 10,
        is_trial: false,
        last_activity_at: new Date().toISOString(),
        tariff_id: null,
        tariff_name: 'Команда',
        mrr_rub: '990.00',
        desired_daily_numbers: 5,
        chargeback_unrecovered_rub: '0.00',
        created_at: new Date().toISOString(),
        ...overrides,
    };
}

const mountView = async () => {
    const router = createRouter({
        history: createMemoryHistory(),
        routes: [
            { path: '/admin/tenants', component: AdminTenantsView },
            { path: '/admin/tenants/:code', name: 'admin-tenant-detail', component: { template: '<div />' } },
        ],
    });
    await router.push('/admin/tenants');
    await router.isReady();
    return mount(AdminTenantsView, {
        global: {
            plugins: [createVuetify(), router],
            stubs: { ImpersonationDialog: true, TenantBalanceDialog: true },
        },
    });
};

describe('AdminTenantsView ↔ GET /api/admin/tenants integration', () => {
    it('listAdminTenants вызывается на mount', async () => {
        vi.mocked(adminApi.listAdminTenants).mockResolvedValueOnce({
            tenants: [],
            total: 0,
            limit: 100,
            offset: 0,
            stats: { total: 0, active: 0, trial: 0, overdue: 0 },
        });

        await mountView();
        await flushPromises();
        expect(adminApi.listAdminTenants).toHaveBeenCalledTimes(1);
    });

    it('успех — replace tenantsState на API-данные + stats', async () => {
        vi.mocked(adminApi.listAdminTenants).mockResolvedValueOnce({
            tenants: [
                makeApiTenant({ id: 100, organization_name: 'Окна Москва', tariff_name: 'Команда' }),
                makeApiTenant({ id: 101, organization_name: 'Двери СПб', tariff_name: 'Pro', is_trial: true }),
            ],
            total: 2,
            limit: 100,
            offset: 0,
            stats: { total: 2, active: 1, trial: 1, overdue: 0 },
        });

        const wrapper = await mountView();
        await flushPromises();

        const vm = wrapper.vm as unknown as {
            tenantsState: { id: number; name: string; status: string }[];
            stats: { total: number; active: number; trial: number; overdue: number };
        };
        expect(vm.tenantsState).toHaveLength(2);
        expect(vm.tenantsState[0].id).toBe(100);
        expect(vm.tenantsState[0].name).toBe('Окна Москва');
        expect(vm.tenantsState[1].status).toBe('trial'); // is_trial=true → 'trial'
        expect(vm.stats.total).toBe(2);
        expect(vm.stats.trial).toBe(1);
    });

    it('reject → fetchError=true + alert виден + tenantsState пустой', async () => {
        vi.mocked(adminApi.listAdminTenants).mockRejectedValueOnce(new Error('500'));

        const wrapper = await mountView();
        await flushPromises();

        const vm = wrapper.vm as unknown as { fetchError: boolean; tenantsState: unknown[] };
        expect(vm.fetchError).toBe(true);
        expect(vm.tenantsState.length).toBe(0); // пустой при ошибке, не mock-fallback
        expect(wrapper.find('[data-testid="fetch-error-alert"]').exists()).toBe(true);
    });

    it('reload-btn вызывает listAdminTenants второй раз', async () => {
        vi.mocked(adminApi.listAdminTenants).mockResolvedValue({
            tenants: [],
            total: 0,
            limit: 100,
            offset: 0,
            stats: { total: 0, active: 0, trial: 0, overdue: 0 },
        });

        const wrapper = await mountView();
        await flushPromises();
        expect(adminApi.listAdminTenants).toHaveBeenCalledTimes(1);

        await wrapper.find('[data-testid="reload-btn"]').trigger('click');
        await flushPromises();
        expect(adminApi.listAdminTenants).toHaveBeenCalledTimes(2);
    });
});

describe('mapApiAdminTenant', () => {
    it('маппит organization_name → name, subdomain → code', () => {
        const m = mapApiAdminTenant(makeApiTenant({ subdomain: 'okna', organization_name: 'Окна' }));
        expect(m.code).toBe('okna');
        expect(m.name).toBe('Окна');
    });

    it('inn пустой (нет в API)', () => {
        const m = mapApiAdminTenant(makeApiTenant());
        expect(m.inn).toBe('');
    });

    it('is_trial=true → status=trial', () => {
        const m = mapApiAdminTenant(makeApiTenant({ is_trial: true }));
        expect(m.status).toBe('trial');
        expect(m.statusText).toBe('Trial');
    });

    it('chargeback>0 → status=overdue', () => {
        const m = mapApiAdminTenant(makeApiTenant({ chargeback_unrecovered_rub: '1000.00' }));
        expect(m.status).toBe('overdue');
    });

    it('balance<0 → status=overdue', () => {
        const m = mapApiAdminTenant(makeApiTenant({ balance_rub: '-200.00' }));
        expect(m.status).toBe('overdue');
    });

    it('schema status=suspended → status=suspended', () => {
        const m = mapApiAdminTenant(makeApiTenant({ status: 'suspended', is_trial: false }));
        expect(m.status).toBe('suspended');
    });

    it('balance_rub строка → number', () => {
        const m = mapApiAdminTenant(makeApiTenant({ balance_rub: '15000.50' }));
        expect(m.balanceRub).toBe(15000.5);
    });

    it('последняя активность форматируется как «X мин назад»', () => {
        const fixedNow = new Date('2026-05-09T10:00:00Z');
        const tenMinAgo = new Date('2026-05-09T09:50:00Z');
        const m = mapApiAdminTenant(makeApiTenant({ last_activity_at: tenMinAgo.toISOString() }), fixedNow);
        expect(m.activitySince).toBe('10 мин назад');
    });

    it('last_activity_at=null → activitySince=«—»', () => {
        const m = mapApiAdminTenant(makeApiTenant({ last_activity_at: null }));
        expect(m.activitySince).toBe('—');
    });

    it('mrr_rub строка → number', () => {
        const m = mapApiAdminTenant(makeApiTenant({ mrr_rub: '990.00' }));
        expect(m.mrrRub).toBe(990);
    });

    it("mrr_rub=null → mrrRub null (для trial и tenant'ов без тарифа)", () => {
        const m = mapApiAdminTenant(makeApiTenant({ mrr_rub: null }));
        expect(m.mrrRub).toBeNull();
    });
});
