import { describe, test, expect, vi, beforeEach } from 'vitest';
import { Client } from '@vulog/aima-client';
import { createBusinessProfile } from './createBusinessProfile';

describe('createBusinessProfile', () => {
    const FLEET_ID = 'HOURCAR-USMSP';
    const USER_ID = '8a274a9c-f5ac-4258-abe1-6c892b6c0b4b';
    const BUSINESS_ID = '051323b4-0f23-4b8d-88b5-d653d20df8ca';
    const REQUEST_ID = '8ee558c1-863e-48cb-9338-e5612ed08d51';

    const postMock = vi.fn();
    const client = {
        post: postMock,
        clientOptions: {
            fleetId: FLEET_ID,
        },
    } as unknown as Client;

    const mockUserProfile = {
        id: '4e0bcb24-8f1a-45b0-9a6b-0817886fa195',
        creationDate: '2026-03-18T13:17:14.208+00:00',
        entityId: 'entity-id',
        entityName: 'default',
        status: 'APPROVED' as const,
        type: 'Business' as const,
        emailConsent: true,
        services: [],
    };

    beforeEach(() => {
        postMock.mockReset();
        postMock.mockResolvedValue({ data: mockUserProfile });
    });

    test('calls POST with correct URL', async () => {
        const data = {
            emailConsent: true,
            email: 'contact@company.com',
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        await createBusinessProfile(client, USER_ID, BUSINESS_ID, data);

        expect(postMock).toHaveBeenCalledTimes(1);
        const [url] = postMock.mock.calls[0];
        expect(url).toBe(
            `/boapi/proxy/business/fleets/${FLEET_ID}/business/${BUSINESS_ID}/user/${USER_ID}`
        );
    });

    test('sends flat profile body (email, emailConsent, requestId) - no userId/businessId in body', async () => {
        const email = 'business.contact@example.com';
        const data = {
            emailConsent: true,
            email,
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        await createBusinessProfile(client, USER_ID, BUSINESS_ID, data);

        const [, body] = postMock.mock.calls[0];
        expect(body).not.toHaveProperty('userId');
        expect(body).not.toHaveProperty('businessId');
        expect(body).not.toHaveProperty('data');
        expect(body).toHaveProperty('email', email);
        expect(body).toHaveProperty('emailConsent', true);
        expect(body).toHaveProperty('requestId', REQUEST_ID);
    });

    test('sends costCenterId when provided', async () => {
        const costCenterId = '018ab2b6-71b2-4c76-90bd-6e8d3f26861c';
        const data = {
            emailConsent: false,
            email: 'biz@example.com',
            requestId: REQUEST_ID,
            costCenterId,
        };

        await createBusinessProfile(client, USER_ID, BUSINESS_ID, data);

        const [, body] = postMock.mock.calls[0];
        expect(body).toEqual({
            emailConsent: false,
            email: 'biz@example.com',
            requestId: REQUEST_ID,
            costCenterId,
        });
    });

    test('omits costCenterId from body when undefined', async () => {
        const data = {
            emailConsent: true,
            email: 'minimal@test.org',
            requestId: REQUEST_ID,
        };

        await createBusinessProfile(client, USER_ID, BUSINESS_ID, data);

        const [, body] = postMock.mock.calls[0];
        expect(body).toHaveProperty('email', 'minimal@test.org');
        expect(body).toHaveProperty('requestId', REQUEST_ID);
        expect(body).toHaveProperty('emailConsent', true);
        expect(body).not.toHaveProperty('costCenterId');
    });

    test('returns response data as UserProfile', async () => {
        const data = {
            emailConsent: true,
            email: 'return@test.com',
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        const result = await createBusinessProfile(
            client,
            USER_ID,
            BUSINESS_ID,
            data
        );

        expect(result).toEqual(mockUserProfile);
        expect(result.id).toBe(mockUserProfile.id);
        expect(result.status).toBe('APPROVED');
        expect(result.type).toBe('Business');
    });

    test('throws TypeError when email is invalid', async () => {
        const data = {
            emailConsent: true,
            email: 'not-an-email',
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        await expect(
            createBusinessProfile(client, USER_ID, BUSINESS_ID, data)
        ).rejects.toThrow(TypeError);

        expect(postMock).not.toHaveBeenCalled();
    });

    test('throws TypeError when email is empty', async () => {
        const data = {
            emailConsent: true,
            email: '',
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        await expect(
            createBusinessProfile(client, USER_ID, BUSINESS_ID, data)
        ).rejects.toThrow(TypeError);

        expect(postMock).not.toHaveBeenCalled();
    });

    test('throws TypeError when userId is not a valid UUID', async () => {
        const data = {
            emailConsent: true,
            email: 'valid@example.com',
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        await expect(
            createBusinessProfile(client, 'not-a-uuid', BUSINESS_ID, data)
        ).rejects.toThrow(TypeError);

        expect(postMock).not.toHaveBeenCalled();
    });

    test('throws TypeError when businessId is not a valid UUID', async () => {
        const data = {
            emailConsent: true,
            email: 'valid@example.com',
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        await expect(
            createBusinessProfile(client, USER_ID, 'invalid-business', data)
        ).rejects.toThrow(TypeError);

        expect(postMock).not.toHaveBeenCalled();
    });

    test('throws TypeError when requestId is not a valid UUID', async () => {
        const data = {
            emailConsent: true,
            email: 'valid@example.com',
            requestId: 'not-a-uuid',
            costCenterId: undefined,
        };

        await expect(
            createBusinessProfile(client, USER_ID, BUSINESS_ID, data)
        ).rejects.toThrow(TypeError);

        expect(postMock).not.toHaveBeenCalled();
    });

    test('throws TypeError when costCenterId is not a valid UUID when provided', async () => {
        const data = {
            emailConsent: true,
            email: 'valid@example.com',
            requestId: REQUEST_ID,
            costCenterId: 'not-a-uuid',
        };

        await expect(
            createBusinessProfile(client, USER_ID, BUSINESS_ID, data)
        ).rejects.toThrow(TypeError);

        expect(postMock).not.toHaveBeenCalled();
    });

    test('error cause includes Zod issues for invalid input', async () => {
        const data = {
            emailConsent: true,
            email: 'bad-email',
            requestId: REQUEST_ID,
            costCenterId: undefined,
        };

        try {
            await createBusinessProfile(client, USER_ID, BUSINESS_ID, data);
        } catch (err) {
            expect(err).toBeInstanceOf(TypeError);
            expect((err as Error).cause).toBeDefined();
            expect(Array.isArray((err as Error).cause)).toBe(true);
        }
    });

    test('sends various valid email formats in body', async () => {
        const emails = [
            'user@example.com',
            'user+tag@sub.domain.co.uk',
            'tneels+biz04@vulog.com',
        ];

        for (const email of emails) {
            postMock.mockClear();
            const data = {
                emailConsent: true,
                email,
                requestId: REQUEST_ID,
                costCenterId: undefined,
            };

            await createBusinessProfile(client, USER_ID, BUSINESS_ID, data);

            const [, body] = postMock.mock.calls[0];
            expect(body.email).toBe(email);
        }
    });
});
