import { action } from 'storybook/actions';
import { Meta, StoryObj } from '@storybook/react-webpack5';

import { Status } from '../common';
import UploadInput, { UploadInputProps } from './UploadInput';
import { UploadedFile, UploadResponse } from './types';
import { userEvent } from 'storybook/test';

const meta: Meta<typeof UploadInput> = {
  title: 'Forms/UploadInput/Tests',
  tags: ['!manifest'],
  component: UploadInput,
};
export default meta;

type Story = StoryObj<UploadInputProps>;

const files: UploadedFile[] = [
  {
    id: '0hd8hf8',
    filename: 'purchase-receipt-0.pdf',
    url: 'https://wise.com/public-resources/assets/logos/wise/brand_logo_inverse.svg',
  },
  {
    id: '1r7hgc83',
    filename: 'purchase-receipt-1.pdf',
  },
  {
    id: '2nhc7387hc8h',
    filename: 'purchase-receipt-2.pdf',
    url: 'https://wise.com/public-resources/assets/logos/wise/brand_logo_inverse.svg',
  },
  {
    id: '39wd8uc',
    filename: 'receipt failed.png',
    status: Status.FAILED,
  },
  {
    id: '437yyf8hf',
    filename: 'receipt failed With error string.png',
    status: Status.FAILED,
    error: 'Something went wrong',
  },
  {
    id: '5biehveifh',
    filename: 'receipt failed With error object.png',
    status: Status.FAILED,
    error: { message: 'Something went wrong' },
  },
];

const createDelayedPromise = async ({
  successful = true,
  delaySeconds = 3,
  response = { id: Math.round(Math.random() * 10000), url: '#' },
}: {
  successful?: boolean;
  delaySeconds?: number;
  response?: UploadResponse;
} = {}): Promise<UploadResponse> =>
  new Promise((resolve, reject) => {
    setTimeout(
      () => (successful ? resolve(response) : reject(new Error('Unexpected error'))),
      delaySeconds * 1000,
    );
  });

const props = {
  onUploadFile: async () => createDelayedPromise(),
  onDeleteFile: async () => createDelayedPromise(),
};

export const UploadInputWithDescriptionFromProps: Story = {
  args: {
    ...props,
    multiple: true,
    description: 'Custom file description from prop',
  },
};

export const Disabled: Story = {
  args: {
    ...props,
    disabled: true,
  },
};

export const WithAnyFileType: Story = {
  args: {
    ...props,
    fileTypes: '*',
  },
};

export const WithSingleFileType: Story = {
  args: {
    ...props,
    fileTypes: '.zip,application/zip',
  },
};

export const WithMultipleExistingFiles: Story = {
  args: {
    ...props,
    files,
    multiple: true,
  },
};

export const WithFileErrors: Story = {
  args: {
    ...props,
    files: [
      { id: 1, filename: 'Error with default message.png', status: Status.FAILED },
      {
        id: 2,
        filename: 'Error with `string` error.png',
        status: Status.FAILED,
        error: 'Single string error',
      },
      {
        id: 3,
        filename: 'Error with `obj` error ({ message : `string` }).png',
        status: Status.FAILED,
        error: { message: 'Single obj error' },
      },
      {
        id: 4,
        filename: 'Error with single error passed in `array`.png',
        status: Status.FAILED,
        errors: ['Single error in array'],
      },
      {
        id: 5,
        filename: 'Error with multiple `string` errors passed in `array`.png',
        status: Status.FAILED,
        errors: [
          'Error 1',
          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
          'Error 3',
        ],
      },
      {
        id: 6,
        filename: 'Error with multiple `obj` errors passed in `array`.png',
        status: Status.FAILED,
        errors: [
          { message: 'Error 1' },
          {
            message:
              'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
          },
          { message: 'Error 3' },
        ],
      },
    ],
    multiple: true,
  },
};

export const WithoutDelete: Story = {
  args: {
    ...props,
    files,
    onDeleteFile: undefined,
    multiple: true,
  },
};

export const WithUploadFailed: Story = {
  args: {
    ...props,
    files: files.slice(0),
    onUploadFile: async () => createDelayedPromise({ successful: false }),
    multiple: true,
  },
};

export const WithDeleteFailed: Story = {
  args: {
    ...props,
    files: files.slice(0),
    onDeleteFile: async () => createDelayedPromise({ successful: false }),
    multiple: true,
  },
};

export const CustomConfirmMessage: Story = {
  args: {
    ...props,
    files: files.slice(0),
    deleteConfirm: {
      title: 'Sure you want to remove this invoice?',
      body: (
        <img
          alt="brand logo"
          src="https://wise.com/public-resources/assets/logos/wise/brand_logo.svg"
        />
      ),
    },
  },
};

export const WithManualDownloadHandler: Story = {
  args: {
    ...props,
    files,
    onDownload: action('Manual download handler'),
  },
};

export const WithFilesChangeHandler: Story = {
  args: {
    ...props,
    files,
    onFilesChange: action('Files change handler'),
  },
};

export const WithMaxFilesToUploadLimit: Story = {
  args: {
    ...props,
    multiple: true,
    maxFiles: 5,
    maxFilesErrorMessage: "Can't upload as maximum number of files allowed are already uploaded",
  },
};

export const WithFileSizeErrorMessage: Story = {
  args: {
    ...props,
    sizeLimit: 1,
    sizeLimitErrorMessage: 'The file is oversized',
  },
};

export const WithNoSizeLimit: Story = {
  args: {
    ...props,
    sizeLimit: null,
  },
};

export const WithCustomUploadButtonTitle: Story = {
  args: {
    ...props,
    uploadButtonTitle: 'Upload the VAT receipts for FY 2022-23',
  },
};

const triggerModalAndConfirm = async ({ isLink = true } = {}) => {
  if (isLink) {
    await wait();
    await userEvent.tab();
  }
  await wait();
  await userEvent.keyboard('{Enter}');
  await wait();
  await userEvent.tab();
  await wait();
  await userEvent.tab();
  await wait();
  await userEvent.tab();
  await wait();
  await userEvent.keyboard('{Enter}');
  await wait();
};
const wait = async (time = 250) =>
  new Promise((resolve) => {
    setTimeout(resolve, time);
  });

export const DeletingTop: Story = {
  args: {
    ...props,
    files: [files[0], files[1], files[2]],
    multiple: true,
  },
  play: async () => {
    await userEvent.tab();
    await triggerModalAndConfirm();
    await triggerModalAndConfirm({ isLink: false });
    await triggerModalAndConfirm();
  },
};

export const DeletingBottom: Story = {
  args: {
    ...props,
    files: [files[0], files[1], files[2]],
    multiple: true,
  },
  play: async () => {
    await userEvent.tab();
    await userEvent.tab();
    await userEvent.tab();
    await userEvent.tab();
    await triggerModalAndConfirm();
    await triggerModalAndConfirm({ isLink: false });
    await triggerModalAndConfirm();
  },
};
