import {
    flushPromises,
    mount,
    type VueWrapper,
} from '@vue/test-utils';
import { nextTick } from 'vue';
import {
    afterEach,
    beforeEach,
    describe,
    expect,
    it,
    vi,
} from 'vitest';

vi.mock('@inertiajs/vue3', async (importOriginal) => {
    const actual = await importOriginal<typeof import('@inertiajs/vue3')>();

    return {
        ...actual,
        Head: {
            name: 'InertiaHeadStub',
            props: { title: String },
            template: '<span data-head />',
        },
    };
});

import PortfolioRecordPage from '@/components/business/PortfolioRecordPage.vue';
import type { PortfolioRecordPayload } from '@/types/business';

const record = (): PortfolioRecordPayload => ({
    kind: 'fund',
    title: 'Demo Alpha Growth IV',
    subtitle: 'Demo Alpha Growth IV SCSp',
    icon: 'folder',
    summary: {
        eyebrow: 'Fund',
        title: 'Demo Alpha Growth IV',
        subtitle: 'Luxembourg SCSp',
        icon: 'folder',
        metrics: [
            { id: 'investors', label: 'Investors', value: '8' },
            { id: 'nav', label: 'NAV', value: 'EUR 38.2m' },
        ],
        details: [
            {
                id: 'gp',
                label: 'General Partner',
                value: 'Demo Arcadia Ventures GmbH',
                link: { href: '/gps/gp-1', inertia: true },
            },
            { id: 'currency', label: 'Currency', value: 'EUR' },
        ],
        aliases: [
            { name: 'Alpha IV', comment: 'Commercial name' },
            { name: 'DAG IV', comment: '' },
        ],
    },
    information: [
        { id: 'strategy', label: 'Strategy', value: 'Growth equity' },
        { id: 'notes', label: 'Notes', value: '<img src=x onerror=alert(1)>', wide: true },
    ],
    tabs: [
        { id: 'information', label: 'Information', icon: 'info' },
        { id: 'investments', label: 'Investments', icon: 'trend-up', badge: 1 },
    ],
    tables: {
        investments: {
            id: 'fund-investments',
            title: 'Investments',
            description: 'Investor commitments linked to this fund.',
            total: 1,
            addLink: {
                href: '/funds/fund-1/investments/create',
                inertia: true,
                label: 'Add investment',
            },
            columns: [
                { key: 'investor', label: 'Investor', type: 'entity' },
                { key: 'commitment', label: 'Commitment', type: 'amount' },
                { key: 'status', label: 'Status', type: 'status' },
            ],
            rows: [{
                id: 'investment-1',
                cells: {
                    investor: { value: '<b>Demo Atlas Pension Trust</b>' },
                    commitment: { value: 1250000, formatted: 'EUR 1.25m' },
                    status: { value: 'active', label: 'Active', variant: 'success' },
                },
                actions: [{
                    id: 'delete-investment',
                    type: 'delete',
                    label: 'Delete investment',
                    url: '/investments/investment-1',
                    confirmTitle: 'Delete investment?',
                    confirm: 'This investor-fund position will be permanently removed.',
                    confirmLabel: 'Delete investment',
                }],
            }],
        },
    },
});

const commonProps = {
    backLink: { href: '/funds', inertia: true, label: 'Back to funds' },
    editLink: { href: '/funds/fund-1/edit', inertia: true },
    destroyAction: {
        href: '/funds/fund-1',
        confirm: {
            title: 'Delete fund?',
            message: 'This fund will be permanently removed.',
            label: 'Delete fund',
        },
    },
};

const flush = async (): Promise<void> => {
    await flushPromises();
    await nextTick();
    await new Promise((resolve) => setTimeout(resolve, 0));
    await nextTick();
};

let wrapper: VueWrapper | null = null;

beforeEach(() => {
    const meta = document.createElement('meta');

    meta.name = 'csrf-token';
    meta.content = 'portfolio-record-token';
    document.head.append(meta);
});

afterEach(() => {
    wrapper?.unmount();
    wrapper = null;
    document.head.querySelector('meta[name="csrf-token"]')?.remove();
    document.body.innerHTML = '';
    vi.restoreAllMocks();
});

describe('PortfolioRecordPage', () => {
    it('renders the mature summary and escaped information tab', () => {
        wrapper = mount(PortfolioRecordPage, {
            props: { record: record(), ...commonProps },
        });

        expect(wrapper.get('.record-summary-card').text()).toContain('EUR 38.2m');
        expect(wrapper.findAll('.record-summary-pill')).toHaveLength(2);
        expect(wrapper.get('.record-summary-pill').attributes('title')).toBe('Commercial name');
        expect(wrapper.get('#fund-detail-tabs_information_panel').attributes('hidden')).toBeUndefined();
        expect(wrapper.get('.business-information-panel').text()).toContain('<img src=x onerror=alert(1)>');
        expect(wrapper.find('.business-information-panel img').exists()).toBe(false);
        expect(wrapper.get('.entity-summary-item--wide').text()).toContain('Notes');
        expect(wrapper.html()).not.toContain('data-ui-');
    });

    it('switches to a typed table and routes delete through one common confirmation', async () => {
        wrapper = mount(PortfolioRecordPage, {
            attachTo: document.body,
            props: { record: record(), ...commonProps },
        });
        const tabs = wrapper.findAll<HTMLButtonElement>('[role="tab"]');

        await tabs[1]?.trigger('click');
        await nextTick();

        expect(tabs[1]?.attributes('aria-selected')).toBe('true');
        expect(wrapper.get('[role="region"]').attributes('aria-label')).toBe('Investments');
        expect(wrapper.text()).toContain('EUR 1.25m');
        expect(wrapper.text()).toContain('<b>Demo Atlas Pension Trust</b>');
        expect(wrapper.find('tbody b').exists()).toBe(false);
        expect(wrapper.get('a[aria-label="Add investment"]').attributes('href')).toBe(
            '/funds/fund-1/investments/create',
        );

        await wrapper.get('button[aria-label="Delete investment"]').trigger('click');
        await flush();

        const dialog = document.body.querySelector<HTMLElement>('[role="alertdialog"]');
        const relatedForm = wrapper.findAll('form').find((form) => (
            form.attributes('action') === '/investments/investment-1'
        ));

        expect(dialog?.textContent).toContain('Delete investment?');
        expect(dialog?.textContent).toContain('This investor-fund position will be permanently removed.');
        expect(relatedForm?.get('input[name="_token"]').attributes('value')).toBe('portfolio-record-token');
        expect(relatedForm?.get('input[name="_method"]').attributes('value')).toBe('DELETE');
    });

    it('uses the shared compact empty state when no extra information is available', () => {
        const payload = record();

        payload.information = [];
        wrapper = mount(PortfolioRecordPage, {
            props: { record: payload, ...commonProps },
        });

        expect(wrapper.get('.ui-empty-state').text()).toContain('No additional information');
        expect(wrapper.get('.ui-empty-state').text()).toContain('No extra workspace fields');
        expect(wrapper.find('.entity-summary').exists()).toBe(false);
    });

    it('renders nested cash-flow and analytical views from the reusable group contract', async () => {
        const payload = record();

        payload.kind = 'investor';
        payload.title = 'Demo Atlas Pension Trust';
        payload.primaryAction = {
            href: '/investors/investor-1/investments/create',
            inertia: true,
            label: 'Investment',
            icon: 'plus',
        };
        payload.tabs = [
            { id: 'investments', label: 'Investments', icon: 'investment', badge: 1 },
            { id: 'cash-flows', label: 'Cash flows', icon: 'transfer' },
            { id: 'analytics', label: 'Analytics', icon: 'chart' },
        ];
        payload.groups = {
            'cash-flows': {
                title: 'Cash flows',
                description: 'Calls, distributions, and reported capital-account positions.',
                label: 'Cash flow views',
                views: [
                    {
                        id: 'call-distribution',
                        label: 'Calls & distributions',
                        icon: 'transfer',
                        description: 'Capital calls and distributions for this investor.',
                        table: {
                            id: 'investor-call-distribs',
                            title: 'Calls & distributions',
                            columns: [{ key: 'amount', label: 'Amount', type: 'amount' }],
                            rows: [{
                                id: 'cash-flow-1',
                                cells: { amount: { value: 500000, formatted: 'EUR 500k' } },
                            }],
                        },
                    },
                    {
                        id: 'capital-accounts',
                        label: 'Capital accounts',
                        icon: 'capital',
                        table: {
                            id: 'investor-capital-accounts',
                            title: 'Capital accounts',
                            columns: [
                                { key: 'nav', label: 'NAV', type: 'amount' },
                                { key: 'tvpi', label: 'TVPI', type: 'multiple' },
                            ],
                            rows: [{
                                id: 'capital-account-1',
                                cells: {
                                    nav: { value: 38200000, formatted: 'EUR 38.2m' },
                                    tvpi: { value: 1.42, formatted: '1.42x' },
                                },
                            }],
                        },
                    },
                ],
            },
            analytics: {
                title: '<strong>Analytics</strong>',
                description: 'Performance and portfolio-allocation analysis.',
                label: 'Analytics views',
                views: [
                    {
                        id: 'performance',
                        label: 'Performance',
                        icon: 'chart',
                        empty: {
                            title: 'No performance observations yet',
                            text: 'Add an investment with performance data.',
                        },
                        metrics: [
                            { id: 'nav', label: 'NAV', value: 'EUR 38.2m', icon: 'capital' },
                            { id: 'tvpi', label: 'Average TVPI', value: '1.42x', icon: 'chart' },
                        ],
                    },
                    {
                        id: 'exposures',
                        label: 'Exposures',
                        icon: 'globe',
                        empty: {
                            title: 'No exposure data yet',
                            text: 'Add an investment with exposure data.',
                        },
                        sections: [{
                            id: 'allocation',
                            title: 'Portfolio allocation',
                            icon: 'globe',
                            fields: [
                                { id: 'currency', label: 'Primary currency', value: 'EUR' },
                                { id: 'strategy', label: 'Primary strategy', value: 'Growth equity' },
                            ],
                        }],
                    },
                ],
            },
        };

        wrapper = mount(PortfolioRecordPage, {
            props: { record: payload, ...commonProps },
        });

        expect(wrapper.get('a.btn-primary').attributes('href'))
            .toBe('/investors/investor-1/investments/create');
        expect(wrapper.get('a.btn-primary').text()).toContain('Investment');

        const cashFlowsTab = wrapper.get<HTMLButtonElement>(
            '#investor-detail-tabs_cash-flows_tab',
        );

        await cashFlowsTab.trigger('click');
        await nextTick();

        expect(cashFlowsTab.attributes('aria-selected')).toBe('true');
        expect(wrapper.get('#investor-cash-flows-views [role="tablist"]').attributes('aria-label'))
            .toBe('Cash flow views');
        expect(wrapper.get('#investor-call-distribs [role="region"]').text()).toContain('EUR 500k');

        await wrapper.get('#investor-cash-flows-views_capital-accounts_tab').trigger('click');
        await nextTick();

        expect(wrapper.get('#investor-cash-flows-views_capital-accounts_panel').attributes('hidden'))
            .toBeUndefined();
        expect(wrapper.get('#investor-capital-accounts [role="region"]').text()).toContain('1.42x');

        await wrapper.get('#investor-detail-tabs_analytics_tab').trigger('click');
        await nextTick();

        const analyticsPanel = wrapper.get('#investor-detail-tabs_analytics_panel');

        expect(analyticsPanel.get('.business-record-group__metrics').text()).toContain('EUR 38.2m');
        expect(analyticsPanel.find('.ui-empty-state').exists()).toBe(false);
        expect(analyticsPanel.get('.business-record-group__header').text())
            .toContain('<strong>Analytics</strong>');
        expect(analyticsPanel.find('.business-record-group__header strong').exists()).toBe(false);

        await wrapper.get('#investor-analytics-views_exposures_tab').trigger('click');
        await nextTick();

        expect(wrapper.get('#investor-analytics-views_exposures_panel').text())
            .toContain('Portfolio allocation');
        expect(wrapper.get('#investor-analytics-views_exposures_panel').text())
            .toContain('Growth equity');
        expect(wrapper.get('#investor-analytics-views_exposures_panel').find('.ui-empty-state').exists())
            .toBe(false);
        expect(wrapper.html()).not.toContain('data-ui-');
    });

    it('lets an empty detail table own the only empty state in a grouped view', () => {
        const payload = record();

        payload.kind = 'investor';
        payload.tabs = [{ id: 'analytics', label: 'Analytics', icon: 'chart' }];
        payload.groups = {
            analytics: {
                title: 'Analytics',
                label: 'Analytics views',
                views: [{
                    id: 'performance',
                    label: 'Performance',
                    table: {
                        id: 'investor-performance',
                        title: 'Performance observations',
                        columns: [{ key: 'fund', label: 'Fund', type: 'entity' }],
                        rows: [],
                        emptyText: 'No performance observations yet.',
                    },
                    empty: {
                        title: 'No performance observations yet',
                        text: 'Performance appears as investments are reported.',
                    },
                }],
            },
        };

        wrapper = mount(PortfolioRecordPage, {
            props: { record: payload, ...commonProps },
        });

        expect(wrapper.findAll('.ui-empty-state')).toHaveLength(1);
        expect(wrapper.get('.ui-empty-state').text()).toContain('No performance observations yet.');
    });
});
