import { useState, useCallback, useContext, useEffect, useRef, useMemo, forwardRef } from 'react';
import { Button, FileInput, FileVisual, Progress, Modal, Text, SummaryList, ViewAll, getKindFromMimeType, getMimeTypeFromFile, Flex, Input, ComboBox, createUID, useModalManager, useModalContext, useToaster, DateTimeDisplay, MetaList, FormDialog } from '@pega/cosmos-react-core';
import { loadingTimeoutMS } from '../../core/Progress/Progress.mocks';
import { FileServiceContext, mockAttachmentListRequest, mockCategories } from '../../core/File/FileService.mock';
const getSummaryListItemProps = ({ ref, file, editFile, cancelFile, deleteFile }) => {
    let actions;
    let visual;
    if ('progress' in file && typeof file.progress === 'number' && file.progress < 100) {
        visual = <Progress value={file.progress} placement='inline' variant='ring'/>;
        actions = [
            {
                id: 'Cancel',
                text: 'Cancel',
                icon: 'times',
                onClick: () => {
                    cancelFile(file.id);
                }
            }
        ];
    }
    else {
        visual = (<FileVisual type={getKindFromMimeType(getMimeTypeFromFile(file.name) ?? '')} thumbnail={file.thumbnail}/>);
        actions = [
            {
                id: 'Edit',
                text: 'Edit',
                icon: 'pencil',
                onClick: () => {
                    editFile?.(file);
                }
            },
            {
                id: 'Download',
                text: 'Download',
                icon: 'download',
                onClick: () => { }
            },
            {
                id: 'Delete',
                text: 'Delete',
                icon: 'trash',
                onClick: () => {
                    deleteFile(file.id);
                }
            }
        ];
    }
    return {
        ref,
        id: file.id,
        visual,
        primary: file.name,
        contextualLabel: file.name,
        secondary: (<Text variant='secondary'>
        {'progress' in file && typeof file.progress === 'number' && file.progress < 100 ? (`Uploading…${Math.floor(file.progress)}%`) : (<MetaList items={[
                    file.category,
                    <>
                Uploaded{' '}
                <DateTimeDisplay variant='relative' value={file.createDate}/>
              </>
                ]}/>)}
      </Text>),
        actions
    };
};
const EditDialog = forwardRef(function EditDialog({ file, target, onSubmit, onCancel }, ref) {
    const [name, setName] = useState(file.name);
    const [error, setError] = useState('');
    const [loading, setLoading] = useState(false);
    const [categories, setCategories] = useState(() => {
        return [
            { id: createUID(), primary: 'No category', selected: false },
            ...mockCategories.map(category => {
                return {
                    id: createUID(),
                    primary: category,
                    selected: file.category === category
                };
            })
        ];
    });
    const selectedCategory = useMemo(() => {
        const sc = categories.find(c => c.selected);
        return sc
            ? {
                items: {
                    id: sc.id,
                    text: sc.primary
                }
            }
            : undefined;
    }, [categories]);
    return (<FormDialog ref={ref} heading='Edit attachment' target={target} progress={loading ? 'Updating attachment...' : undefined} placement='bottom-start' onCancel={onCancel} onSubmit={() => {
            if (error)
                return;
            setLoading(true);
            setTimeout(() => {
                onSubmit({
                    name,
                    category: !selectedCategory || selectedCategory.items.text === 'No category'
                        ? ''
                        : selectedCategory.items.text
                });
                setLoading(false);
            }, loadingTimeoutMS);
        }}>
      <Flex container={{ direction: 'column', gap: 2 }}>
        <Input label='Name' placeholder='Enter name…' value={name} info={error} status={error ? 'error' : undefined} autoFocus required onChange={(e) => {
            setName(e.target.value);
            if (error && e.target.value) {
                setError('');
            }
        }} onBlur={() => {
            if (!name) {
                setError('Name is required.');
            }
        }}/>
        <ComboBox label='Category' placeholder='Choose…' selected={selectedCategory} menu={{
            mode: 'single-select',
            items: categories,
            onItemClick: id => {
                setCategories(cur => {
                    return cur.map(category => {
                        return {
                            ...category,
                            selected: category.id === id
                        };
                    });
                });
            }
        }}/>
      </Flex>
    </FormDialog>);
});
const AttachmentsModal = ({ defaultMode }) => {
    const [mode, setMode] = useState(defaultMode);
    const { push: pushToaster } = useToaster();
    const { dismiss } = useModalContext();
    const { files, setFiles, cancelFile, attachFile, deleteFile } = useContext(FileServiceContext);
    const [search, setSearch] = useState('');
    const [viewAllLoading, setViewAllLoading] = useState(true);
    const [addNewLoading, setAddNewLoading] = useState(false);
    const [newFiles, setNewFiles] = useState([]);
    const attachSelected = useCallback(() => {
        newFiles.forEach(attachFile);
        dismiss();
    }, [newFiles, attachFile]);
    const listItemEls = useRef([]);
    const [editFileIndex, setEditFileIndex] = useState(-1);
    const editDialogTargetLi = useMemo(() => {
        return editFileIndex !== undefined ? listItemEls.current[editFileIndex] : undefined;
    }, [editFileIndex, listItemEls]);
    const menuButton = useMemo(() => editDialogTargetLi
        ? editDialogTargetLi.querySelector('button[aria-haspopup="menu"]')
        : null, [editDialogTargetLi]);
    const handleDialogClose = useCallback(() => {
        if (!editDialogTargetLi)
            return;
        setEditFileIndex(-1);
        menuButton?.focus();
    }, [menuButton, editDialogTargetLi]);
    const handleKeydown = useCallback((e) => {
        if (e.key === 'Escape') {
            setEditFileIndex(-1);
        }
    }, []);
    const editDialogRef = useRef(null);
    useEffect(() => {
        if (mode === 'viewAll') {
            const timeout = setTimeout(() => {
                setViewAllLoading(false);
            }, 1000);
            return () => {
                clearTimeout(timeout);
            };
        }
    }, [mode]);
    useEffect(() => {
        if (!editDialogTargetLi)
            return;
        document.addEventListener('keydown', handleKeydown);
        return () => {
            document.removeEventListener('keydown', handleKeydown);
        };
    }, [editDialogTargetLi]);
    useEffect(() => {
        listItemEls.current = [];
    }, [mode]);
    const onFilesAdded = useCallback((newlyAddedFiles) => {
        setNewFiles(current => [
            ...newlyAddedFiles.map((file, i) => {
                const id = createUID();
                return {
                    id,
                    name: file.name,
                    format: file.name.split('.').pop(),
                    category: '',
                    File: file,
                    onEdit: () => {
                        setEditFileIndex(i);
                    },
                    onCancel: () => {
                        setNewFiles(c => c.filter(f => f.id !== id));
                    }
                };
            }),
            ...current
        ]);
    }, [files]);
    const actions = mode === 'addNew' ? (<>
        <Button onClick={dismiss} disabled={addNewLoading}>
          Cancel
        </Button>
        <Button type='submit' variant='primary' onClick={() => {
            setAddNewLoading(true);
            setTimeout(() => {
                attachSelected();
                setAddNewLoading(false);
            }, loadingTimeoutMS);
        }} disabled={newFiles.length === 0 || addNewLoading}>
          Upload files
        </Button>
      </>) : null;
    const content = mode === 'addNew' ? (<FileInput multiple label='Select files to upload' onFilesAdded={onFilesAdded} files={newFiles.map(f => ({ ...f, meta: f.category || undefined }))}/>) : (<ViewAll loading={viewAllLoading} items={(search ? files.filter(f => f.name.includes(search)) : files).map((file, i) => {
            return getSummaryListItemProps({
                ref: (el) => {
                    listItemEls.current[i] = el;
                },
                file,
                editFile: () => {
                    setEditFileIndex(i);
                },
                cancelFile: id => {
                    const canceledFile = files.find(f => f.id === id);
                    cancelFile(id);
                    pushToaster({ content: `Cancelled uploading ${canceledFile.name}` });
                },
                deleteFile: async (id) => {
                    const deletedFile = files.find(f => f.id === id);
                    await deleteFile(id);
                    pushToaster({ content: `${deletedFile.name} deleted` });
                }
            });
        })} actions={[
            {
                id: 'addNewFile',
                text: 'Add files',
                onClick: () => {
                    setMode('addNew');
                }
            },
            {
                id: 'addNewLink',
                text: 'Add links',
                onClick: () => {
                    setMode('addNew');
                }
            }
        ]} searchInputProps={{ onSearchChange: value => setSearch(value) }}/>);
    return (<Modal as={mode === 'addNew' ? 'form' : undefined} heading={mode === 'addNew' ? 'Add attachments' : 'Attachments'} actions={actions} progress={addNewLoading ? { message: 'Adding attachments...' } : undefined} onRequestDismiss={() => {
            return !editDialogTargetLi;
        }} onSubmit={mode === 'addNew'
            ? (e) => {
                e.preventDefault();
            }
            : undefined}>
      <>
        {content}
        {editDialogTargetLi && menuButton && (<EditDialog ref={editDialogRef} target={menuButton} file={mode === 'addNew' ? newFiles[editFileIndex] : files[editFileIndex]} onCancel={handleDialogClose} onSubmit={({ name, category }) => {
                handleDialogClose();
                if (mode === 'addNew') {
                    setNewFiles(cur => {
                        return cur.map((file, i) => {
                            if (i === editFileIndex) {
                                return {
                                    ...file,
                                    name,
                                    category
                                };
                            }
                            return file;
                        });
                    });
                }
                else {
                    setFiles(cur => cur.map((file, i) => {
                        if (i === editFileIndex) {
                            return {
                                ...file,
                                name,
                                category
                            };
                        }
                        return file;
                    }));
                }
            }}/>)}
      </>
    </Modal>);
};
export const AttachmentsMock = () => {
    const { push: pushToaster } = useToaster();
    const { create: createModal } = useModalManager();
    const [loading, setLoading] = useState(true);
    const { files, setFiles, cancelFile, deleteFile } = useContext(FileServiceContext);
    const listItemEls = useRef([]);
    const [editFileIndex, setEditFileIndex] = useState(-1);
    const editDialogTargetLi = useMemo(() => {
        return editFileIndex !== undefined ? listItemEls.current[editFileIndex] : undefined;
    }, [editFileIndex, listItemEls]);
    const menuButton = useMemo(() => editDialogTargetLi
        ? editDialogTargetLi.querySelector('button[aria-haspopup="menu"]')
        : null, [editDialogTargetLi]);
    const handleDialogClose = useCallback(() => {
        if (!editDialogTargetLi)
            return;
        setEditFileIndex(-1);
        menuButton?.focus();
    }, [menuButton, editDialogTargetLi]);
    const handleKeydown = useCallback((e) => {
        if (e.key === 'Escape') {
            setEditFileIndex(-1);
        }
    }, []);
    const editDialogRef = useRef(null);
    useEffect(() => {
        let mounted = true;
        (async () => {
            const attachments = await mockAttachmentListRequest();
            if (mounted) {
                setLoading(false);
                setFiles(attachments);
            }
        })();
        return () => {
            mounted = false;
        };
    }, []);
    useEffect(() => {
        if (!editDialogTargetLi)
            return;
        document.addEventListener('keydown', handleKeydown);
        return () => {
            document.removeEventListener('keydown', handleKeydown);
        };
    }, [editDialogTargetLi]);
    return (<>
      <SummaryList icon='paper-clip' name='Attachments' headingTag='h3' loading={loading} count={!loading && Array.isArray(files) ? files.length : undefined} actions={[
            {
                text: 'Add',
                id: 'addNew',
                icon: 'plus',
                onClick() {
                    createModal(AttachmentsModal, { defaultMode: 'addNew' });
                }
            }
        ]} items={files.slice(0, 3).map((file, i) => {
            return getSummaryListItemProps({
                ref: (el) => {
                    listItemEls.current[i] = el;
                },
                file,
                editFile: () => {
                    setEditFileIndex(i);
                },
                cancelFile: id => {
                    const canceledFile = files.find(f => f.id === id);
                    cancelFile(id);
                    pushToaster({ content: `Cancelled uploading ${canceledFile.name}` });
                },
                deleteFile: async (id) => {
                    const deletedFile = files.find(f => f.id === id);
                    await deleteFile(id);
                    pushToaster({ content: `${deletedFile.name} deleted` });
                }
            });
        })} onViewAll={() => {
            createModal(AttachmentsModal, { defaultMode: 'viewAll' });
        }}/>
      {editDialogTargetLi && menuButton && (<EditDialog ref={editDialogRef} target={menuButton} file={files[editFileIndex]} onCancel={handleDialogClose} onSubmit={({ name, category }) => {
                handleDialogClose();
                setFiles(cur => cur.map((file, i) => {
                    if (i === editFileIndex) {
                        return {
                            ...file,
                            name,
                            category
                        };
                    }
                    return file;
                }));
            }}/>)}
    </>);
};
//# sourceMappingURL=Attachments.mocks.jsx.map