import React from 'react'
import '@/components/ReactPlayground/CodeEditor/FileSelector/file-selector.scss'
import { IFiles } from '@/components/ReactPlayground/shared'
import { ENTRY_FILE_NAME, IMPORT_MAP_FILE_NAME } from '@/components/ReactPlayground/files'
import Item from '@/components/ReactPlayground/CodeEditor/FileSelector/Item'
import HideScrollbar, { HideScrollbarElement } from '@/components/common/HideScrollbar'
import FlexBox from '@/components/common/FlexBox'

interface FileSelectorProps {
    files?: IFiles
    onChange?: (fileName: string) => void
    onError?: (msg: string) => void
    readonly?: boolean
    notRemovableFiles?: string[]
    onRemoveFile?: (fileName: string) => void
    onAddFile?: (fileName: string) => void
    onUpdateFileName?: (newFileName: string, oldFileName: string) => void
    selectedFileName?: string
}

const FileSelector: React.FC<FileSelectorProps> = ({
    files = {},
    onChange,
    onError,
    readonly = false,
    notRemovableFiles = [],
    onRemoveFile,
    onAddFile,
    onUpdateFileName,
    selectedFileName = ''
}) => {
    const hideScrollbarRef = useRef<HideScrollbarElement>(null)
    const [tabs, setTabs] = useState<string[]>([])
    const [creating, setCreating] = useState(false)
    const [hasEditing, setHasEditing] = useState(false)

    const getMaxSequenceTabName = (filesName: string[]) => {
        const result = filesName.reduce((max, filesName) => {
            const match = filesName.match(/Component(\d+)\.tsx/)
            if (match) {
                const sequenceNumber = parseInt(match[1], 10)
                return Math.max(Number(max), sequenceNumber)
            }
            return max
        }, 0)

        return `Component${result + 1}.tsx`
    }

    const addTab = () => {
        setTabs([...tabs, getMaxSequenceTabName(tabs)])
        setCreating(true)
        setTimeout(() => {
            hideScrollbarRef.current?.scrollRight(1000)
        })
    }

    const handleOnCancel = () => {
        if (!creating) {
            return
        }

        tabs.pop()
        setTabs([...tabs])
        setCreating(false)
    }

    const handleOnClickTab = (fileName: string) => {
        if (creating) {
            return
        }

        onChange?.(fileName)
    }

    const editImportMap = () => {
        onChange?.(IMPORT_MAP_FILE_NAME)
    }

    const handleOnSaveTab = (value: string, item: string) => {
        if (creating) {
            onAddFile?.(value)
            setCreating(false)
        } else {
            onUpdateFileName?.(value, item)
        }

        setTimeout(() => {
            handleOnClickTab(value)
        })
    }

    const handleOnValidateTab = (newFileName: string, oldFileName: string) => {
        if (!/\.(jsx|tsx|js|ts|css|json|svg)$/.test(newFileName)) {
            onError?.(
                'Playground only supports *.jsx, *.tsx, *.js, *.ts, *.css, *.json, *.svg files.'
            )

            return false
        }

        if (tabs.includes(newFileName) && newFileName !== oldFileName) {
            onError?.(`File "${newFileName}" already exists.`)
            return false
        }

        return true
    }

    const handleOnRemove = (fileName: string) => {
        onRemoveFile?.(fileName)
        if (fileName === selectedFileName) {
            const index = Object.keys(files).indexOf(fileName) - 1
            if (index >= 0) {
                handleOnClickTab(Object.keys(files)[index])
            } else {
                handleOnClickTab(Object.keys(files)[1])
            }
        }
    }

    useEffect(() => {
        Object.keys(files).length &&
            setTabs(
                Object.keys(files).filter(
                    (item) =>
                        ![IMPORT_MAP_FILE_NAME, ENTRY_FILE_NAME].includes(item) &&
                        !files[item].hidden
                )
            )
    }, [files])

    return (
        <>
            <div data-component={'playground-file-selector'} className={'tab'}>
                <div className={'multiple'}>
                    <HideScrollbar ref={hideScrollbarRef}>
                        <FlexBox direction={'horizontal'} className={'tab-content'}>
                            {tabs.map((item, index) => (
                                <Item
                                    key={index + item}
                                    value={item}
                                    active={selectedFileName === item}
                                    creating={creating}
                                    readonly={readonly || notRemovableFiles.includes(item)}
                                    hasEditing={hasEditing}
                                    setHasEditing={setHasEditing}
                                    onValidate={handleOnValidateTab}
                                    onOk={(name) => handleOnSaveTab(name, item)}
                                    onCancel={handleOnCancel}
                                    onRemove={handleOnRemove}
                                    onClick={() => handleOnClickTab(item)}
                                />
                            ))}
                            {!readonly && (
                                <Item
                                    className={'tab-item-add'}
                                    value={'+'}
                                    onClick={addTab}
                                    readonly
                                />
                            )}
                            <div className={'tabs-margin-right'}>
                                <div />
                            </div>
                        </FlexBox>
                    </HideScrollbar>
                </div>
                <div className={'sticky'}>
                    <Item
                        value={'Import Map'}
                        active={selectedFileName === IMPORT_MAP_FILE_NAME}
                        onClick={editImportMap}
                        readonly
                    />
                </div>
            </div>
        </>
    )
}

export default FileSelector
