import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';
import { useCartStore } from '@/stores/cartStore';
import PromotionPanel from '@/components/POS/PromotionPanel';
import PosItem from '@/components/POS/PosItem';

// Mock the cart store
jest.mock('@/stores/cartStore');
jest.mock('react-hot-toast', () => ({
    success: jest.fn(),
    error: jest.fn(),
}));

// Mock fetch
global.fetch = jest.fn();

const mockUseCartStore = useCartStore as jest.MockedFunction<typeof useCartStore>;

const createTestWrapper = () => {
    const queryClient = new QueryClient({
        defaultOptions: {
            queries: { retry: false },
            mutations: { retry: false },
        },
    });

    return ({ children }: { children: React.ReactNode }) => (
        <QueryClientProvider client={queryClient}>
            <BrowserRouter>
                {children}
            </BrowserRouter>
        </QueryClientProvider>
    );
};

describe('PromotionPanel Integration', () => {
    beforeEach(() => {
        jest.clearAllMocks();

        // Mock cart store default values
        mockUseCartStore.mockReturnValue({
            appliedPromotions: [],
            freeItems: [],
            voucherCode: '',
            setVoucherCode: jest.fn(),
            applyPromotions: jest.fn(),
            isLoading: false,
            errors: [],
            warnings: [],
            customerId: null,
            locationId: null,
            items: [],
            totals: {
                subtotal: 0,
                discount: 0,
                tax: 0,
                total: 0,
            },
            addItem: jest.fn(),
            updateItemQuantity: jest.fn(),
            removeItem: jest.fn(),
            setCustomerId: jest.fn(),
            setLocationId: jest.fn(),
            clearCart: jest.fn(),
            clearPromotions: jest.fn(),
            setTotals: jest.fn(),
            setLoading: jest.fn(),
            setErrors: jest.fn(),
            setWarnings: jest.fn(),
        });
    });

    it('renders promotion panel with voucher input', () => {
        render(<PromotionPanel />, { wrapper: createTestWrapper() });

        expect(screen.getByText('Promotions & Vouchers')).toBeInTheDocument();
        expect(screen.getByPlaceholderText('Enter promo code...')).toBeInTheDocument();
        expect(screen.getByText('Apply')).toBeInTheDocument();
    });

    it('applies voucher code when entered', async () => {
        const mockApplyPromotions = jest.fn();
        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            applyPromotions: mockApplyPromotions,
        });

        render(<PromotionPanel />, { wrapper: createTestWrapper() });

        const voucherInput = screen.getByPlaceholderText('Enter promo code...');
        const applyButton = screen.getByText('Apply');

        fireEvent.change(voucherInput, { target: { value: 'SAVE10' } });
        fireEvent.click(applyButton);

        await waitFor(() => {
            expect(mockApplyPromotions).toHaveBeenCalled();
        });
    });

    it('displays applied promotions', () => {
        const mockPromotions = [
            {
                id: 1,
                name: 'Buy 2 Get 1 Free',
                discount_type: 'free',
                discount_value: 0,
                applied_items: [1, 2],
                free_items: [3],
                voucher_code: 'SAVE10',
                customer_targeting: 'all',
            },
        ];

        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            appliedPromotions: mockPromotions,
        });

        render(<PromotionPanel />, { wrapper: createTestWrapper() });

        expect(screen.getByText('Buy 2 Get 1 Free')).toBeInTheDocument();
        expect(screen.getByText('FREE')).toBeInTheDocument();
        expect(screen.getByText('Voucher: SAVE10')).toBeInTheDocument();
    });

    it('displays free items', () => {
        const mockFreeItems = [
            {
                product_id: 3,
                category_id: 1,
                name: 'Hair Serum',
                qty: 1,
                promotion_id: 1,
                promotion_name: 'Buy 2 Get 1 Free',
            },
        ];

        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            freeItems: mockFreeItems,
        });

        render(<PromotionPanel />, { wrapper: createTestWrapper() });

        expect(screen.getByText('Free Items (1)')).toBeInTheDocument();
        expect(screen.getByText('Hair Serum')).toBeInTheDocument();
        expect(screen.getByText('FREE')).toBeInTheDocument();
    });

    it('displays errors and warnings', () => {
        const mockErrors = ['Invalid voucher code'];
        const mockWarnings = ['Promotion expired'];

        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            errors: mockErrors,
            warnings: mockWarnings,
        });

        render(<PromotionPanel />, { wrapper: createTestWrapper() });

        expect(screen.getByText('Invalid voucher code')).toBeInTheDocument();
        expect(screen.getByText('Promotion expired')).toBeInTheDocument();
    });

    it('shows loading state', () => {
        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            isLoading: true,
        });

        render(<PromotionPanel />, { wrapper: createTestWrapper() });

        expect(screen.getByText('Applying promotions...')).toBeInTheDocument();
    });
});

describe('PosItem Integration', () => {
    const mockItem = {
        product_id: 1,
        category_id: 1,
        name: 'Shampoo',
        qty: 2,
        price: 50.00,
        total: 100.00,
        discount: 0,
        discount_type: 'value' as const,
        is_free: false,
        promotion_id: undefined,
        promotion_name: undefined,
        parent_item_id: undefined,
        selection_strategy: undefined,
        allocated_discount: undefined,
    };

    const mockHandlers = {
        onQuantityChange: jest.fn(),
        onRemove: jest.fn(),
    };

    beforeEach(() => {
        jest.clearAllMocks();

        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            appliedPromotions: [],
        });
    });

    it('renders item without promotion badges', () => {
        render(
            <PosItem
                item={mockItem}
                onQuantityChange={mockHandlers.onQuantityChange}
                onRemove={mockHandlers.onRemove}
                showPromotionBadges={false}
            />,
            { wrapper: createTestWrapper() }
        );

        expect(screen.getByText('Shampoo')).toBeInTheDocument();
        expect(screen.getByText('Qty: 2')).toBeInTheDocument();
        expect(screen.getByText('EGP 100.00')).toBeInTheDocument();
        expect(screen.queryByText('FREE')).not.toBeInTheDocument();
    });

    it('renders item with promotion badges', () => {
        const itemWithPromotion = {
            ...mockItem,
            promotion_id: 1,
            promotion_name: 'Buy 2 Get 1 Free',
            is_free: true,
        };

        const mockPromotions = [
            {
                id: 1,
                name: 'Buy 2 Get 1 Free',
                discount_type: 'free',
                discount_value: 0,
                applied_items: [1],
                free_items: [1],
            },
        ];

        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            appliedPromotions: mockPromotions,
        });

        render(
            <PosItem
                item={itemWithPromotion}
                onQuantityChange={mockHandlers.onQuantityChange}
                onRemove={mockHandlers.onRemove}
                showPromotionBadges={true}
            />,
            { wrapper: createTestWrapper() }
        );

        expect(screen.getByText('Shampoo')).toBeInTheDocument();
        expect(screen.getByText('FREE')).toBeInTheDocument();
        expect(screen.getByText('From: Buy 2 Get 1 Free')).toBeInTheDocument();
    });

    it('handles quantity changes', () => {
        render(
            <PosItem
                item={mockItem}
                onQuantityChange={mockHandlers.onQuantityChange}
                onRemove={mockHandlers.onRemove}
                showControls={true}
            />,
            { wrapper: createTestWrapper() }
        );

        const plusButton = screen.getByRole('button', { name: /plus/i });
        const minusButton = screen.getByRole('button', { name: /minus/i });

        fireEvent.click(plusButton);
        expect(mockHandlers.onQuantityChange).toHaveBeenCalledWith(1, 3);

        fireEvent.click(minusButton);
        expect(mockHandlers.onQuantityChange).toHaveBeenCalledWith(1, 1);
    });

    it('handles item removal', () => {
        render(
            <PosItem
                item={mockItem}
                onQuantityChange={mockHandlers.onQuantityChange}
                onRemove={mockHandlers.onRemove}
                showControls={true}
            />,
            { wrapper: createTestWrapper() }
        );

        const removeButton = screen.getByRole('button', { name: /remove/i });
        fireEvent.click(removeButton);

        expect(mockHandlers.onRemove).toHaveBeenCalledWith(1);
    });

    it('shows discount information', () => {
        const itemWithDiscount = {
            ...mockItem,
            discount: 10.00,
        };

        render(
            <PosItem
                item={itemWithDiscount}
                onQuantityChange={mockHandlers.onQuantityChange}
                onRemove={mockHandlers.onRemove}
            />,
            { wrapper: createTestWrapper() }
        );

        expect(screen.getByText('-EGP 10.00 discount')).toBeInTheDocument();
    });

    it('shows conflict warning for manual discount', () => {
        const itemWithDiscountAndPromotion = {
            ...mockItem,
            discount: 10.00,
            promotion_id: 1,
            promotion_name: 'Test Promotion',
        };

        const mockPromotions = [
            {
                id: 1,
                name: 'Test Promotion',
                discount_type: 'percentage',
                discount_value: 10,
                applied_items: [1],
                free_items: [],
            },
        ];

        mockUseCartStore.mockReturnValue({
            ...mockUseCartStore(),
            appliedPromotions: mockPromotions,
        });

        render(
            <PosItem
                item={itemWithDiscountAndPromotion}
                onQuantityChange={mockHandlers.onQuantityChange}
                onRemove={mockHandlers.onRemove}
                showPromotionBadges={true}
            />,
            { wrapper: createTestWrapper() }
        );

        expect(screen.getByText('Manual discount overridden by promotion')).toBeInTheDocument();
    });
});

describe('Cart Store Integration', () => {
    it('should handle promotion state correctly', () => {
        const { result } = renderHook(() => useCartStore(), {
            wrapper: createTestWrapper(),
        });

        // Test initial state
        expect(result.current.appliedPromotions).toEqual([]);
        expect(result.current.freeItems).toEqual([]);
        expect(result.current.voucherCode).toBe('');

        // Test adding item
        const testItem = {
            product_id: 1,
            category_id: 1,
            name: 'Test Item',
            qty: 1,
            price: 10.00,
            total: 10.00,
        };

        act(() => {
            result.current.addItem(testItem);
        });

        expect(result.current.items).toContainEqual(testItem);

        // Test setting voucher
        act(() => {
            result.current.setVoucherCode('SAVE10');
        });

        expect(result.current.voucherCode).toBe('SAVE10');

        // Test clearing cart
        act(() => {
            result.current.clearCart();
        });

        expect(result.current.items).toEqual([]);
        expect(result.current.appliedPromotions).toEqual([]);
        expect(result.current.freeItems).toEqual([]);
    });
});
