import React from 'react';
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import demoTest from '../../../tests/demoTest';
import mountTest from '../../../tests/mountTest';
import { defaultContext } from '../../context-provider';
import Uploader from '..';
import '@testing-library/jest-dom';

demoTest('uploader');

mountTest(Uploader, 'Uploader');

const prefix = `${defaultContext.prefixCls}-uploader`;

const FILE_DATA =
    'data:image/svg+xml;base64, ';

const mockFile = new File([FILE_DATA], 'img.png', { type: 'image/png' });

describe('Uploader', () => {
    beforeEach(() => {
        jest.useFakeTimers();
        jest.spyOn(global, 'FileReader').mockImplementation(function () {
            this.readAsDataURL = jest.fn();
            this.onload = jest.fn();
            this.onerror = jest.fn();
        });
    });
    afterEach(() => {
        jest.useRealTimers();
        jest.restoreAllMocks();
    });
    it('Uploader renders correctly', () => {
        const { container } = render(<Uploader files={[]} />);
        expect(container.querySelectorAll(`.${prefix}-add`).length).toBe(1);
    });
    it('Uploader renders correctly', () => {
        const { container } = render(<Uploader files={[{ file: mockFile }, { file: mockFile }]} />);
        expect(container.querySelectorAll(`.${prefix}-list`).length).toBe(1);
        expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(2);
    });
    it('Uploader renders correctly', () => {
        const { container } = render(
            <Uploader files={[{ file: mockFile }, { file: mockFile }]} limit={1} />,
        );
        expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(1);
    });
    it('Uploader renders correctly', () => {
        const { container, rerender } = render(
            <Uploader files={[{ file: mockFile }, { file: mockFile }]} limit={1} />,
        );
        expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(1);
        rerender(<Uploader files={[]} limit={1} />);
        expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(0);
    });
    it('onChange listener correctly', () => {
        const onChange = jest.fn();
        const { container } = render(<Uploader files={[{ file: mockFile }]} onChange={onChange} />);
        container.querySelector(`.${prefix}-list-item-delete`);
        userEvent.click(container.querySelector(`.${prefix}-list-item-delete`));
        expect(onChange.mock.calls.length).toBe(1);
    });
    it('upload correctly', async () => {
        function App() {
            const [files, setFiles] = React.useState([]);
            return <Uploader files={files} onChange={setFiles} />;
        }
        const { container } = render(<App />);
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        const input = container.querySelector('input');
        await userEvent.upload(input, mockFile);
        const reader = FileReader.mock.instances[0];
        reader.onload({ target: { result: 'foo' } });
        await waitFor(() => {
            expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(1);
        });
    });
    it('custom upload', async () => {
        function App() {
            async function mockUpload() {
                return {
                    file: mockFile,
                };
            }
            const [files, setFiles] = React.useState([]);
            return <Uploader files={files} onChange={setFiles} upload={mockUpload} />;
        }
        const { container } = render(<App />);
        const selectors = container.querySelectorAll(`.${prefix}-add`);
        const inputs = container.querySelectorAll('input');
        await userEvent.click(selectors[0]);
        await userEvent.upload(inputs[0], mockFile);
        const reader = FileReader.mock.instances[0];
        reader.onload({ target: { result: 'foo' } });
        await waitFor(() => {
            expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(1);
        });
    });
    it('upload maxSize', async () => {
        function App({ onMaxSizeExceed }) {
            const [files, setFiles] = React.useState([]);
            return (
                <Uploader
                    maxSize={1}
                    files={files}
                    onChange={setFiles}
                    onMaxSizeExceed={onMaxSizeExceed}
                />
            );
        }
        const handleMaxSizeExceed = jest.fn();
        const { container } = render(<App onMaxSizeExceed={handleMaxSizeExceed} />);
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        const input = container.querySelector('input');
        await userEvent.upload(input, mockFile);
        await waitFor(() => {
            expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(0);
        });
        await waitFor(() => {
            expect(handleMaxSizeExceed).toBeCalledTimes(1);
        });
    });
    it('upload limit', async () => {
        function App({ onLimitExceed }) {
            const [files, setFiles] = React.useState([]);
            return (
                <Uploader
                    multiple
                    limit={1}
                    files={files}
                    onChange={setFiles}
                    onLimitExceed={onLimitExceed}
                />
            );
        }
        const handlLimitExceed = jest.fn();
        const { container } = render(<App onLimitExceed={handlLimitExceed} />);
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        const input = container.querySelector('input');
        await userEvent.upload(input, [mockFile, mockFile, mockFile]);
        const reader = FileReader.mock.instances[0];
        reader.onload({ target: { result: 'foo' } });
        await waitFor(() => {
            expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(1);
        });
        await waitFor(() => {
            expect(handlLimitExceed).toBeCalledTimes(1);
        });
    });
    it('click file list item correctly', () => {
        const handleClick = jest.fn();
        const { container } = render(
            <Uploader files={[{ file: mockFile }]} onClick={handleClick} />,
        );
        userEvent.click(container.querySelector(`.${prefix}-list-item`));
        expect(handleClick).toBeCalledTimes(1);
    });
    it('selectAdapter', async () => {
        const handleMaxSizeExceed = jest.fn();
        const handleLimitExceed = jest.fn();
        function App({ onMaxSizeExceed, onLimitExceed }) {
            const [files, setFiles] = React.useState([{ file: mockFile }, { file: mockFile }]);
            const selectAdapter = () => {
                return new Promise(resolve => {
                    const selectFiles = [
                        {
                            name: '11vnpmryrl4.jpeg',
                            size: 789020,
                            type: 'image/jpeg',
                            url: 'http://sf1-cdn-tos.toutiaostatic.com/obj/arco-mobile/_static_/large_image_1.jpg',
                        },
                        {
                            name: '11vnpmryrl2.jpeg',
                            size: 7820,
                            type: 'image/jpeg',
                            url: 'http://sf1-cdn-tos.toutiaostatic.com/obj/arco-mobile/_static_/large_image_2.jpg',
                        },
                        {
                            name: '11vnpmryrl1.jpeg',
                            size: 7820,
                            type: 'image/jpeg',
                            url: 'http://sf1-cdn-tos.toutiaostatic.com/obj/arco-mobile/_static_/large_image_3.jpg',
                        },
                    ];
                    resolve({ files: selectFiles });
                });
            };
            return (
                <Uploader
                    files={files}
                    onChange={setFiles}
                    selectAdapter={selectAdapter}
                    limit={3}
                    maxSize={100}
                    multiple
                    onMaxSizeExceed={onMaxSizeExceed}
                    onLimitExceed={onLimitExceed}
                />
            );
        }
        const { container } = render(
            <App onMaxSizeExceed={handleMaxSizeExceed} onLimitExceed={handleLimitExceed} />,
        );
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        await waitFor(() => {
            expect(container.querySelectorAll(`.${prefix}-list-item`).length).toBe(3);
        });
        await waitFor(() => {
            expect(handleMaxSizeExceed).toBeCalledTimes(1);
        });
        await waitFor(() => {
            expect(handleLimitExceed).toBeCalledTimes(1);
        });
    });
});
