import React from 'react';
import { screen } from '@testing-library/react';
import { createIdentity, renderInAppContext } from '@theorchard/suite-testing';
import { ABACUS_PROFILE } from 'src/constants';
import CreateTransferForm, {
    buildProjects,
    buildProjectSearchOptions,
    buildIdLookupOption,
    mergeProjectOptions,
    selectProject,
} from '../create-transfer/create-transfer-form';

const identity = createIdentity({ profileType: ABACUS_PROFILE });
const noop = () => {};

const makeProduct = (
    overrides?: Partial<Parameters<typeof buildProjects>[0][0]>
) => ({
    upc: '123456789',
    productName: 'Test Album',
    project: {
        projectId: '42',
        projectName: 'My Project',
        projectCode: 'MYCODE',
    },
    tracks: [],
    ...overrides,
});

describe('buildProjects', () => {
    it('captures projectCode from product project', () => {
        const [proj] = buildProjects([makeProduct()]);
        expect(proj.projectCode).toBe('MYCODE');
    });

    it('sets projectCode to null when absent', () => {
        const product = makeProduct();
        product.project = {
            projectId: '42',
            projectName: 'No Code',
            projectCode: null,
        };
        const [proj] = buildProjects([product]);
        expect(proj.projectCode).toBeNull();
    });

    it('groups products by projectId', () => {
        const products = [makeProduct({ upc: 'A' }), makeProduct({ upc: 'B' })];
        const projects = buildProjects(products);
        expect(projects).toHaveLength(1);
        expect(projects[0].upcs).toHaveLength(2);
    });
});

describe('buildProjectSearchOptions', () => {
    const makeSummary = (
        overrides?: Partial<Parameters<typeof buildProjectSearchOptions>[0][0]>
    ) => ({
        projectId: 42,
        projectName: 'My Project',
        projectCode: 'MYCODE',
        productCount: 9,
        vendorId: 101,
        ...overrides,
    });

    it('maps a project summary to an option with id, code and real count', () => {
        const [opt] = buildProjectSearchOptions([makeSummary()]);
        expect(opt).toEqual({
            label: 'My Project',
            value: '42',
            subtitle: '42 · MYCODE · 9 Products',
        });
    });

    it('singularizes a product count of one', () => {
        const [opt] = buildProjectSearchOptions([
            makeSummary({ productCount: 1 }),
        ]);
        expect(opt.subtitle).toBe('42 · MYCODE · 1 Product');
    });

    it('omits a missing code and a missing count', () => {
        const [opt] = buildProjectSearchOptions([
            makeSummary({ projectCode: null, productCount: null }),
        ]);
        expect(opt.subtitle).toBe('42');
        expect(opt.subtitle).not.toContain('Product');
    });
});

describe('buildIdLookupOption', () => {
    const summary = {
        projectId: 5877627,
        projectName: 'Myke After Sale',
        projectCode: 'mas',
        productCount: 9,
        vendorId: 25464,
        subaccountId: 88046,
    };

    it('surfaces an exact-id project under the origin vendor and subaccount', () => {
        const opts = buildIdLookupOption(summary, 25464, 88046);
        expect(opts).toHaveLength(1);
        expect(opts[0].value).toBe('5877627');
    });

    it('drops a project that belongs to a different vendor', () => {
        expect(
            buildIdLookupOption({ ...summary, vendorId: 999 }, 25464, 88046)
        ).toEqual([]);
    });

    it('drops a project in a different subaccount when one is in scope', () => {
        expect(
            buildIdLookupOption({ ...summary, subaccountId: 1 }, 25464, 88046)
        ).toEqual([]);
    });

    it('matches on vendor alone when the account has no subaccount scope', () => {
        expect(buildIdLookupOption(summary, 25464, undefined)).toHaveLength(1);
    });

    it('returns nothing when the lookup found no project', () => {
        expect(buildIdLookupOption(null, 25464, 88046)).toEqual([]);
    });

    it('returns nothing when no origin vendor is selected', () => {
        expect(buildIdLookupOption(summary, undefined, 88046)).toEqual([]);
    });
});

describe('mergeProjectOptions', () => {
    // An exact Project ID match, surfaced ahead of the name-search results.
    const idOption = {
        label: 'Myke After Sale',
        value: '5877627',
        subtitle: '5877627 · mas · 9 Products',
    };
    const nameOption = {
        label: 'Other Project',
        value: '111',
        subtitle: '111 · oth · 2 Products',
    };

    it('prepends the id match ahead of the name results', () => {
        const merged = mergeProjectOptions([idOption], [nameOption]);
        expect(merged.map(o => o.value)).toEqual(['5877627', '111']);
    });

    it('dedupes by projectId and keeps the primary (id) entry', () => {
        const sameProjectByName = {
            label: 'Myke After Sale',
            value: '5877627',
            subtitle: '5877627',
        };
        const merged = mergeProjectOptions([idOption], [sameProjectByName]);
        expect(merged).toHaveLength(1);
        expect(merged[0].subtitle).toBe('5877627 · mas · 9 Products');
    });

    it('returns the name results when there is no id match', () => {
        expect(mergeProjectOptions([], [nameOption])).toEqual([nameOption]);
    });
});

describe('selectProject', () => {
    // The selected project's full product/track tree is what the terms step
    // needs; it is built on demand from the products fetched for the picked
    // project and narrowed to its projectId, so it stays exact.
    it('builds the selected project tree from fetched products', () => {
        const result = selectProject(
            [makeProduct({ upc: 'A' }), makeProduct({ upc: 'B' })],
            '42'
        );
        expect(result?.id).toBe('42');
        expect(result?.upcs).toHaveLength(2);
    });

    it('returns undefined when the projectId is not among the products', () => {
        expect(selectProject([makeProduct()], '999')).toBeUndefined();
    });

    it('returns undefined when no project is selected', () => {
        expect(selectProject([makeProduct()], undefined)).toBeUndefined();
    });

    // allProductsSearch returns project.projectId as an Int (number), but the
    // picker's projectId comes from the project lookup as a String. selectProject
    // must still match them, or the picked project never resolves and Next
    // stays disabled.
    it('matches a numeric API projectId against the string picker value', () => {
        const product = makeProduct({
            project: {
                projectId: 5877627 as unknown as string,
                projectName: 'Myke After Sale',
                projectCode: 'mas',
            },
        });
        expect(selectProject([product], '5877627')?.id).toBe('5877627');
    });
});

describe('CreateTransferForm', () => {
    it('renders the modal title when open', () => {
        renderInAppContext(
            <CreateTransferForm isOpen onClose={noop} onSuccess={noop} />,
            { identity }
        );
        expect(screen.getByText('Create New Transfer')).toBeInTheDocument();
    });

    it('renders nothing when closed', () => {
        renderInAppContext(
            <CreateTransferForm
                isOpen={false}
                onClose={noop}
                onSuccess={noop}
            />,
            { identity }
        );
        expect(
            screen.queryByText('Create New Transfer')
        ).not.toBeInTheDocument();
    });

    it('Next button is disabled when no fields are filled', () => {
        renderInAppContext(
            <CreateTransferForm isOpen onClose={noop} onSuccess={noop} />,
            { identity }
        );
        expect(screen.getByRole('button', { name: 'Next' })).toBeDisabled();
    });
});
