// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import { Spinner } from "@coreai-ds/react-components";
import { Badge } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowClockwise20Regular } from "@fluentui/react-icons";
import { Delete20Regular } from "@fluentui/react-icons";
import { MessageBar } from "@coreai-ds/react-components";
import { MessageBarBody } from "@coreai-ds/react-components";
import { MessageBarTitle } from "@coreai-ds/react-components";
import { FileUpload } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

export const WithFileGrid = () => {
    type UploadStatus = 'pending' | 'uploading' | 'uploaded' | 'failed';
    interface UploadItem {
        id: string;
        name: string;
        size: number;
        status: UploadStatus;
    }
    const maxFileSize = 5 * 1024 * 1024;
    const acceptedFileTypes = {
        'application/pdf': ['.pdf'],
        'text/plain': ['.txt'],
        'image/png': ['.png'],
        'image/jpeg': ['.jpg', '.jpeg'],
    };
    const initialFiles: UploadItem[] = [
        {
            id: 'product-guide.pdf',
            name: 'product-guide.pdf',
            size: 1842176,
            status: 'uploaded',
        },
    ];
    const createUploadItem = (file: File): UploadItem => ({
        id: `${file.name}-${file.lastModified}-${file.size}`,
        name: file.name,
        size: file.size,
        status: 'pending',
    });
    const formatFileSize = (bytes: number): string => {
        const megabytes = bytes / (1024 * 1024);
        return `${megabytes.toLocaleString(undefined, { maximumFractionDigits: 2 })} MB`;
    };
    const instructionsId = React.useId();
    const errorId = React.useId();
    const [files, setFiles] = React.useState<UploadItem[]>(initialFiles);
    const [error, setError] = React.useState<string>();
    const handleRetry = (file: UploadItem) => {
        setFiles((prev) => prev.map((item) => (item.id === file.id ? { ...item, status: 'uploading' } : item)));
        window.setTimeout(() => {
            setFiles((prev) => prev.map((item) => (item.id === file.id ? { ...item, status: 'uploaded' } : item)));
        }, 800);
    };
    const handleDelete = (file: UploadItem) => {
        setFiles((prev) => prev.filter((item) => item.id !== file.id));
    };
    const renderUploadStatus = (status: UploadStatus): React.ReactNode => {
        if (status === 'uploading') {
            return <Spinner as="span" label="Uploading" labelPosition="after" size="tiny"/>;
        }
        if (status === 'uploaded') {
            return (<Badge appearance="tint" color="success">
            Uploaded
          </Badge>);
        }
        if (status === 'failed') {
            return (<Badge appearance="tint" color="danger">
            Failed
          </Badge>);
        }
        return 'Pending';
    };
    const columns = [
        {
            columnId: 'name',
            compare: (a: UploadItem, b: UploadItem) => a.name.localeCompare(b.name),
            renderHeaderCell: () => 'Name',
            renderCell: (item: UploadItem) => <TableCellLayout truncate>{item.name}</TableCellLayout>,
        },
        {
            columnId: 'size',
            compare: (a: UploadItem, b: UploadItem) => a.size - b.size,
            renderHeaderCell: () => 'Size',
            renderCell: (item: UploadItem) => (<TableCellLayout>{formatFileSize(item.size)}</TableCellLayout>),
        },
        {
            columnId: 'status',
            compare: (a: UploadItem, b: UploadItem) => a.status.localeCompare(b.status),
            renderHeaderCell: () => 'Status',
            renderCell: (item: UploadItem) => (<TableCellLayout>{renderUploadStatus(item.status)}</TableCellLayout>),
        },
        {
            columnId: 'actions',
            compare: () => 0,
            renderHeaderCell: () => 'Actions',
            renderCell: (item: UploadItem) => (<TableCellLayout className="file-upload-grid-example__actions">
            {item.status === 'failed' ? (<Button appearance="subtle" aria-label={`Retry ${item.name}`} icon={<ArrowClockwise20Regular aria-hidden/>} onClick={() => handleRetry(item)}/>) : null}
            <Button appearance="subtle" aria-label={`Delete ${item.name}`} disabled={item.status === 'uploading'} icon={<Delete20Regular aria-hidden/>} onClick={() => handleDelete(item)}/>
          </TableCellLayout>),
        },
    ];
    const handleFilesAdded = (added: readonly File[]) => {
        setError(undefined);
        setFiles((prev) => {
            const next = [...prev];
            for (const file of added) {
                const item = createUploadItem(file);
                if (!next.some((existing) => existing.id === item.id)) {
                    next.push(item);
                }
            }
            return next;
        });
        // Simulate upload progress for newly added files.
        for (const file of added) {
            const id = createUploadItem(file).id;
            window.setTimeout(() => {
                setFiles((prev) => prev.map((item) => (item.id === id ? { ...item, status: 'uploading' } : item)));
            }, 200);
            window.setTimeout(() => {
                setFiles((prev) => prev.map((item) => item.id === id
                    ? {
                        ...item,
                        status: file.name.toLowerCase().includes('fail') ? 'failed' : 'uploaded',
                    }
                    : item));
            }, 1200);
        }
    };
    const styles = /* css */ `
    .file-upload-grid-example {
      display: flex;
      flex-direction: column;
      max-width: 720px;
      padding: var(--spacingHorizontalL);
      row-gap: var(--spacingVerticalL);
    }

    .file-upload-grid-example__actions {
      align-items: center;
      column-gap: var(--spacingHorizontalXXS);
      display: flex;
    }
  `;
    return (<>
        <style>{styles}</style>
        <div className="file-upload-grid-example">
          {error ? (<MessageBar id={errorId} intent="error">
              <MessageBarBody>
                <MessageBarTitle>Unable to add file</MessageBarTitle>
                {error}
              </MessageBarBody>
            </MessageBar>) : null}

          <FileUpload accept={acceptedFileTypes} ariaDescribedBy={error ? `${instructionsId} ${errorId}` : instructionsId} ariaLabel="Choose files" maxSize={maxFileSize} minSize={1} multiple onDropAccepted={handleFilesAdded} onDropRejected={(rejections) => setError(rejections
            .map(({ file, errors }) => `${file.name}: ${errors.map(({ message }) => message).join(', ')}`)
            .join('; '))}>
            <Text preset="body">Drag files here or click to browse</Text>
            <Text id={instructionsId} foreground={3} preset="bodyS">
              PDF, TXT, PNG, or JPEG · Max 5 MB
            </Text>
          </FileUpload>

          {files.length === 0 ? (<Text foreground={3} preset="bodyS">
              No files yet. Drop or browse to add some.
            </Text>) : (<DataGrid aria-label="Selected files" columns={columns} getRowId={(item) => item.id} items={files} sortable>
              <DataGridHeader>
                <DataGridRow>
                  {({ renderHeaderCell }) => (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
                </DataGridRow>
              </DataGridHeader>
              <DataGridBody<UploadItem>>
                {({ item, rowId }) => (<DataGridRow<UploadItem> key={rowId}>
                    {({ renderCell, columnId }) => (<DataGridCell focusMode={columnId === 'actions' ? 'group' : undefined}>
                        {renderCell(item)}
                      </DataGridCell>)}
                  </DataGridRow>)}
              </DataGridBody>
            </DataGrid>)}
        </div>
      </>);
};

export default WithFileGrid;
