import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';
import { sbCompPrefix } from '../../global/storybook-utils';
import { CvFileUploader, CvFileUploaderSkeleton } from '.';
import { KINDS, STATES } from './const';
import { action } from '@storybook/addon-actions';
import { nextTick, ref, watch, onMounted } from 'vue';
import { Add16 } from '@carbon/icons-vue';
import { buttonKinds, buttonSizes } from '../CvButton/consts';

<Meta title={`${sbCompPrefix}/CvFileUploader`} component={CvFileUploader} />

export const Template = args => ({
  components: {
    CvFileUploader,
    CvFileUploaderSkeleton,
    Add16
  },
  setup() {
    const fileUploader = ref(null);
    const files = ref(storage.files);
    // exposed methods handlers
    function clear() {
      if (args.clear && args.clear > storage.clearCount) {
        storage.clearCount = args.clear;
        fileUploader.value.clear();
        action('cv-file-uploader clear')()
      }
    }
    function remove() {
      if (args.remove && args.remove > storage.removeCount && files.value.length > 0) {
        const randomIndex = Math.floor(Math.random() * files.value.length);
        storage.removeCount = args.remove;
        fileUploader.value.remove(randomIndex);
        action('cv-file-uploader remove')(randomIndex)
      }
    }
    function setInvalidMessage(index) {
      if (files.value[index].invalidMessage !== args.setInvalidMessage) {
        fileUploader.value.setInvalidMessage(index, args.setInvalidMessage);
        action('cv-file-uploader setInvalidMessage')(index, args.setInvalidMessage);
      }
    }
    function setState(index) {
      const newState = setStateOptionMap[args.setState];
      if (files.value[index].state !== newState) {
        fileUploader.value.setState(index, newState);
        action('cv-file-uploader setState')(index, newState);
      }
    }
    // exposed methods setState & setInvalidMessage handler
    function changeFiles() {
      const callbacks = [
        typeof args.setState === 'string' ? setState : null,
        typeof args.setInvalidMessage === 'string' ? setInvalidMessage : null,
      ];
      files.value.forEach((_, index) => callbacks.forEach(callback => callback && callback(index)));
    }
    watch(() => files.value, (newValue) => {
      storage.files = newValue;
      changeFiles();
    }, { deep: true });
    onMounted(() => {
      clear();
      remove();
      changeFiles();
    });
    return {
      fileUploader,
      files,
      slotContent: args.slot,
      args: {
        ...args,
        template: undefined,
      },
    };
  },
  template: args.template,
});
const storage = {
  files: [],
  clearCount: 0,
  removeCount: 0,
};
const setStateOptionMap = {
  [`Set files status to: None`]: STATES.NONE,
  [`Set files status to: Complete (${STATES.COMPLETE})`]: STATES.COMPLETE,
  [`Set files status to: Uploading (${STATES.UPLOADING})`]: STATES.UPLOADING,
};
const defaultTemplate = `
  <div style="display: inline-flex; align-items: flex-start;">
    <cv-file-uploader v-bind="args" ref="fileUploader" v-model="files" />
  </div>
`;
const slotTemplate = `
  <div style="display: inline-flex; align-items: flex-start;">
    <cv-file-uploader v-bind="args">
      <template v-slot:drop-target>
        <Add16 />
        <span>File Drop</span>
        <Add16 />
      </template>
    </cv-file-uploader>
  </div>
`;
const skeletonTemplate = `
  <div style="display: inline-flex; align-items: flex-start;">
    <cv-file-uploader-skeleton />
  </div>
`;

export const argTypes = {
  // attributes
  multiple: {
    type: 'boolean',
    defaultValue: true,
    table: {
      type: { summary: 'boolean' },
      category: 'props',
    },
    description: 'standard input attribute for file type, allow multiple files to be added in a single prompt',
  },
  // props
  accept: {
    type: 'string',
    defaultValue: '.jpg,.png',
    table: {
      type: { summary: 'string' },
      category: 'props',
    },
    description: 'standard input attribute for file type',
  },
  buttonKind: {
    control: 'select',
    options: buttonKinds,
    defaultValue: 'primary',
    table: {
      type: { summary: 'string' },
      category: 'props',
      defaultValue: { summary: 'primary' },
    },
    description: 'Button kind',
  },
  buttonLabel: {
    type: 'string',
    deprecated: true,
    table: {
      type: { summary: 'string' },
      category: 'props',
    },
    description: '`button-label` prop deprecated in favour of drop-target-label',
  },
  buttonSize: {
    control: 'select',
    options: buttonSizes,
    defaultValue: '',
    table: {
      type: { summary: 'string' },
      category: 'props',
      defaultValue: { summary: '' },
    },
    description: 'Button size',
  },
  clearOnReselect: {
    type: 'boolean',
    table: {
      type: { summary: 'boolean' },
      category: 'props',
    },
    description: 'Reset file list when files are added',
  },
  disabled: {
    type: 'boolean',
    table: {
      type: { summary: 'boolean' },
      category: 'props',
    },
    description: 'Disables input',
  },
  dropTargetLabel: {
    type: 'string',
    table: {
      type: { summary: 'string' },
      category: 'props',
    },
    description: "Drag & drop zone label. Also used as button label for button kind file uploader",
  },
  helperText: {
    type: 'string',
    table: {
      type: { summary: 'string' },
      category: 'props',
    },
    description: 'Helper text positioned below label',
  },
  initialStateUploading: {
    type: 'boolean',
    table: {
      type: { summary: 'boolean' },
      category: 'props',
    },
    description: 'Set "UPLOADING" state to new files',
  },
  kind: {
    type: 'string',
    control: 'select',
    defaultValue: KINDS.DRAG_TARGET,
    options: [KINDS.DRAG_TARGET, KINDS.BUTTON],
    table: {
      type: { summary: `${KINDS.DRAG_TARGET} | ${KINDS.BUTTON}` },
      category: 'props',
      defaultValue: { summary: KINDS.DRAG_TARGET },
    },
    description: 'Kind of file uploader to present',
  },
  label: {
    table: {
      type: { summary: 'text' },
      category: 'props',
    },
    description: 'File input label',
  },
  removable: {
    type: 'boolean',
    table: {
      type: { summary: 'boolean' },
      category: 'props',
    },
    description: 'Enable file items remove button',
  },
  removeAriaLabel: {
    type: 'string',
    defaultValue: 'Remove selected file',
    table: {
      type: { summary: 'string' },
      category: 'props',
      defaultValue: { summary: 'Remove selected file' },
    },
    description: 'Aria label for item remove button',
  },
  // exposed methods
  clear: {
    control: 'button',
    buttonLabel: 'Clear',
    type: 'function',
    table: {
      type: { summary: '() => void' },
      category: 'exposed methods',
    },
    description: 'Clear file list',
  },
  remove: {
    control: 'button',
    buttonLabel: 'Remove a random file',
    type: 'function',
    table: {
      type: { summary: '(index: number) => void' },
      category: 'exposed methods',
    },
    description: 'Removes an individual file',
  },
  setInvalidMessage: {
    control: 'text',
    type: 'function',
    table: {
      type: { summary: '(index: number, invalidMessage: string) => void' },
      category: 'exposed methods',
    },
    description: 'Update the "invalidMessage" field of a file.',
  },
  setState: {
    control: 'select',
    options: Object.keys(setStateOptionMap),
    type: 'function',
    table: {
      type: { summary: '(index: number, state: string) => void' },
      category: 'exposed methods',
    },
    description: 'Update the "state" field of a file. State must be `""`, `complete` or `uploading`',
  },
  // slots
  'drop-target': {
    control: 'none',
    type: 'string',
    table: {
      type: { summary: 'string | HTML | Component' },
      category: 'slots',
    },
    description: 'Overrides the drop-target-label with slotted content',
  },
};

# CvFileUploader

Migration notes:

- The `v-model` is different in Vue 3 than Vue 2. You can still specify the `v-model="something"` for two way data bind,
  but the value property is now `modelValue` instead of `files` and event linked to v-model is `update:modelValue`.

<Canvas>
  <Story
    name="Default"
    parameters={{
      controls: {
        exclude: [
          'template',
          'props',
          'modelValue',
          'update:modelValue',
        ],
      },
      docs: { source: { code: defaultTemplate } },
    }}
    args={{
      template: defaultTemplate,
      label: 'Choose files to upload',
      helperText: 'Select the files you want to upload',
      removable: true,
    }}
    argTypes={argTypes}
  >
    {Template.bind({})}
  </Story>
</Canvas>

<ArgsTable story="Default" />

# CvFileUploader Button

<Canvas>
  <Story
    name="FilerUploader Button"
    parameters={{
      controls: {
        exclude: [
          'template',
          'props',
          'modelValue',
          'update:modelValue',
        ],
      },
      docs: { source: { code: defaultTemplate } },
    }}
    args={{
      template: defaultTemplate,
      label: 'Choose files to upload',
      helperText: 'Select the files you want to upload',
      kind: KINDS.BUTTON,
      removable: true,
      dropTargetLabel: 'Add file',
    }}
    argTypes={{
      ...argTypes,
      kind: {
        ...argTypes.kind,
        control: 'none',
      },
    }}
  >
    {Template.bind({})}
  </Story>
</Canvas>

# CvFileUploader Slotted

<Canvas>
  <Story
    name="Slot"
    parameters={{
      controls: {
        exclude: [
          'template',
          'props',
          'modelValue',
          'update:modelValue',
        ],
      },
      docs: { source: { code: slotTemplate } },
    }}
    args={{
      template: slotTemplate,
      label: 'Choose files to upload',
      helperText: 'Select the files you want to upload',
      removable: true,
    }}
    argTypes={{
      ...argTypes,
      kind: {
        ...argTypes.kind,
        control: 'none',
      },
    }}
  >
    {Template.bind({})}
  </Story>
</Canvas>

# CvFileUploaderSkeleton

<Canvas>
  <Story
    name="Skeleton"
    parameters={{
      controls: {
        exclude: [
          'template',
        ],
      },
      docs: { source: { code: skeletonTemplate } },
    }}
    args={{
      template: skeletonTemplate,
    }}
    argTypes={{}}
  >
    {Template.bind({})}
  </Story>
</Canvas>
