import { useDocuments, useDownload, useFolders } from '../hooks/swrHooks'
import { IDocument, IDocumentFolder } from '../interfaces/documents'
import { Box, Breadcrumbs, Button, CircularProgress, Divider, IconButton, Link, List, ListItemButton, SxProps } from '@mui/material'
import { Cancel, Close, Download, Folder, InsertDriveFile, Upload, UploadFile } from '@mui/icons-material'
import React, { useEffect, useRef, useState } from 'react'
import DocumentService from '../services/DocumentService'
import { mutate } from 'swr'
import FileViewer from './modals/FileViewer'

interface FolderProps {
    folder: IDocumentFolder;
    index: number;
    handleFolderClick: (folder: IDocumentFolder) => void;
}

interface DocumentProps {
    doc: IDocument;
    index: number;
    handleDocumentClick: (index: number) => void;
}

const FileItemStyle: SxProps = {
    cursor: 'pointer',
    display: 'flex',
    width: '100%',
    flexDirection: 'row',
    gap: '8px',
    alignItems: 'center',
    padding: '8px'
}

function ItemFolder({ folder, handleFolderClick, ...props }: FolderProps) {
    return (
        <ListItemButton
            onClick={() => handleFolderClick(folder)}
        >
            <Box
                sx={FileItemStyle}
                {...props}
            >
                <Folder />
                {folder.name}
            </Box>
        </ListItemButton>
    )
}

const handleSave = async (file: Blob, filename: string) => {
    const link = document.createElement('a')
    link.href = window.URL.createObjectURL(file)
    link.download = filename
    link.click()
    link.remove()
    window.URL.revokeObjectURL(link.href)
}

function ItemDocument({ doc, index, handleDocumentClick, ...props }: DocumentProps) {
    const [shouldFetch, setShouldFetch] = useState(false)

    const { file, isLoading } = useDownload(shouldFetch ? doc?.document_folder_id : null, shouldFetch ? doc?.id : null)

    useEffect(() => {
        if (shouldFetch) {
            if (file) {
                handleSave(file, doc.name)
                setShouldFetch(false)
            }
        }
    }, [shouldFetch, file])

    return (
        <ListItemButton>
            <Box
                sx={FileItemStyle}
                onClick={() => handleDocumentClick(index)}
                {...props}
            >
                <InsertDriveFile />
                {doc.name}
            </Box>
            <Box>
                <IconButton
                    onClick={() => {
                        if (!isLoading) {
                            setShouldFetch(true)
                        }
                    }}
                    sx={{ ml: 'auto' }}
                >
                    {isLoading ?
                        <CircularProgress size={24} variant='indeterminate' />
                        :
                        <Download />
                    }
                </IconButton>
            </Box>
        </ListItemButton>
    )
}

export default function FolderViewer() {
    const [currentFolder, setCurrentFolder] = useState<IDocumentFolder | null>(null)
    const [breadcrumbs, setBreadcrumbs] = useState<IDocumentFolder[]>([])
    const { folders, isLoading: foldersLoading } = useFolders()
    const { documents, isLoading: documentsLoading } = useDocuments(currentFolder?.id)
    const [uploadProgress, setUploadProgress] = useState(0)
    const [isUploading, setIsUploading] = useState(false)
    const fileInputRef = useRef<HTMLInputElement>(null)
    const [fileViewerModal, setFileViewerModal] = useState(false)
    const [currentFileNo, setCurrentFileNo] = useState<number>(-1)

    const [dragOver, setDragOver] = useState(false)
    const [filesToUpload, setFilesToUpload] = useState<File[]>([])

    const handleFolderClick = (folder: IDocumentFolder) => {
        setCurrentFolder(folder)
        setBreadcrumbs((prev) => [...prev, folder])
    }

    const handleDocumentClick = async (index: number) => {
        setCurrentFileNo(index)
        setFileViewerModal(true)
    }

    const handleBreadcrumbClick = (index: number) => {
        const newBreadcrumbs = breadcrumbs.slice(0, index + 1);
        setBreadcrumbs(newBreadcrumbs)
        setCurrentFolder(newBreadcrumbs[newBreadcrumbs.length - 1])
    }

    const handleUploadClick = () => {
        if (fileInputRef.current) {
            fileInputRef.current.click()
        }
    }

    const handleDragOver = (e: React.DragEvent) => {
        e.preventDefault()
        setDragOver(true)
    }

    const handleDragLeave = () => {
        setDragOver(false)
    }

    const handleDrop = (e: React.DragEvent) => {
        e.preventDefault()
        setDragOver(false)
        const files = Array.from(e.dataTransfer.files)
        setFilesToUpload((prevFiles) => [...prevFiles, ...files])
    }

    const handleFileInput = (e: React.ChangeEvent<HTMLInputElement>) => {
        const files = Array.from(e.target.files || [])
        setFilesToUpload((prevFiles) => [...prevFiles, ...files])
    }

    const uploadFiles = async () => {
        setIsUploading(true)
        if (filesToUpload.length > 0 && currentFolder && currentFolder.id) {
            const formData = new FormData()
            for (const file of filesToUpload) {
                formData.append('files', file)
            }
            try {
                await DocumentService.uploadFiles(currentFolder.id, formData, setUploadProgress);
                setIsUploading(false);
                setFilesToUpload([]);
                mutate(`/info/documents/${currentFolder.id}`);
            } catch (error) {
                console.error(error);
                setIsUploading(false);
            }
        }
    }

    if (foldersLoading || documentsLoading) {
        return (
            <CircularProgress />
        )
    }

    return (
        <Box sx={{
            display: 'flex',
            flexDirection: 'column',
            gap: '16px',
            p: '16px'
        }}>
            <FileViewer
                open={fileViewerModal}
                setOpen={setFileViewerModal}
                currentFileNo={currentFileNo}
                setCurrentFileNo={setCurrentFileNo}
                docs={documents}
            />

            <Breadcrumbs>
                <Link
                    underline='hover'
                    color='inherit'
                    onClick={() => {
                        setCurrentFolder(null)
                        setBreadcrumbs([])
                    }}
                    sx={{ cursor: 'pointer' }}
                >
                    Главная
                </Link>

                {breadcrumbs.map((breadcrumb, index) => (
                    <Link
                        key={breadcrumb.id}
                        underline="hover"
                        color="inherit"
                        onClick={() => handleBreadcrumbClick(index)}
                        sx={{ cursor: 'pointer' }}
                    >
                        {breadcrumb.name}
                    </Link>
                ))}
            </Breadcrumbs>

            {currentFolder &&
                <Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
                    <Box sx={{
                        display: 'flex',
                        flexDirection: 'column',
                        gap: '16px',
                        border: filesToUpload.length > 0 ? '1px dashed gray' : 'none',
                        borderRadius: '8px',
                        p: '16px'
                    }}>
                        <Box sx={{ display: 'flex', gap: '16px' }}>
                            <Button
                                LinkComponent="label"
                                role={undefined}
                                variant="outlined"
                                tabIndex={-1}
                                startIcon={
                                    isUploading ? <CircularProgress sx={{ maxHeight: "20px", maxWidth: "20px" }} variant="determinate" value={uploadProgress} /> : <UploadFile />
                                }
                                onClick={handleUploadClick}
                            >
                                <input
                                    type='file'
                                    ref={fileInputRef}
                                    style={{ display: 'none' }}
                                    onChange={handleFileInput}
                                    onClick={(e) => {
                                        if (e.currentTarget) {
                                            e.currentTarget.value = ''
                                        }
                                    }}
                                />
                                Добавить
                            </Button>

                            {filesToUpload.length > 0 &&
                                <>
                                    <Button
                                        variant="contained"
                                        color="primary"
                                        startIcon={<Upload />}
                                        onClick={uploadFiles}
                                    >
                                        Загрузить все
                                    </Button>

                                    <Button
                                        variant='outlined'
                                        startIcon={<Cancel />}
                                        onClick={() => {
                                            setFilesToUpload([])
                                        }}
                                    >
                                        Отмена
                                    </Button>
                                </>
                            }
                        </Box>

                        <Divider />

                        {filesToUpload.length > 0 &&
                            <Box>
                                {filesToUpload.map((file, index) => (
                                    <Box key={index} sx={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '8px' }}>
                                        <Box>
                                            <InsertDriveFile />
                                            <span>{file.name}</span>
                                        </Box>

                                        <IconButton sx={{ ml: 'auto' }} onClick={() => {
                                            setFilesToUpload(prev => {
                                                return prev.filter((_, i) => i != index)
                                            })
                                        }}>
                                            <Close />
                                        </IconButton>
                                    </Box>
                                ))}
                            </Box>
                        }
                    </Box>
                </Box>
            }

            <List
                dense
                onDragOver={handleDragOver}
                onDragLeave={handleDragLeave}
                onDrop={handleDrop}
                sx={{
                    backgroundColor: dragOver ? 'rgba(0, 0, 0, 0.1)' : 'inherit'
                }}
            >
                {currentFolder ? (
                    documents?.map((doc: IDocument, index: number) => (
                        <div key={`${doc.id}-${doc.name}`}>
                            <ItemDocument
                                doc={doc}
                                index={index}
                                handleDocumentClick={handleDocumentClick}
                            />
                            {index < documents.length - 1 && <Divider />}
                        </div>
                    ))
                ) : (
                    folders?.map((folder: IDocumentFolder, index: number) => (
                        <div key={`${folder.id}-${folder.name}`}>
                            <ItemFolder
                                folder={folder}
                                index={index}
                                handleFolderClick={handleFolderClick}
                            />
                            {index < folders.length - 1 && <Divider />}
                        </div>
                    ))
                )}
            </List>
        </Box>
    )
}