import React, { useState } from 'react';
import { Dialog } from '@/components/elements/dialog';
import { Button } from '@/components/elements/button/index';
import { Form, Formik } from 'formik';
import { object, string } from 'yup';
import Field from '@/components/elements/Field';
import Code from '@/components/elements/Code';
import Label from '@/components/elements/Label';
import Select from '@/components/elements/Select';
import { getTemplates, type FileTemplate } from '../main/components/SettingsDialog';
import RenameModal from '../modals/RenameModal';
import PermissionsModal from '../modals/PermissionsModal';
import TrashBinModal from '../modals/TrashBinModal';
import TrashCleanupSettingsModal from '../modals/TrashCleanupSettingsModal';
import { PullUrlInlineForm } from '../modals/PullUrlModal';
import { type TrashCleanupSettings } from '../api/server/files/betterFilesApi';

interface Props {
    modalTargetPath: string;
    modalTargetMode?: string;
    currentPath: string;
    showRenameModal: boolean;
    showPermissionsModal: boolean;
    showDeleteConfirm: boolean;
    showMoveToTrashConfirm: boolean;
    showUnarchiveConfirm: boolean;
    showCreateModal: boolean;
    showUploadPickerModal: boolean;
    showTrashBinModal: boolean;
    showTrashCleanupModal: boolean;
    actionMode: 'file' | 'folder';
    uploadMode: 'device' | 'url';
    targetDirectories: string[];
    uploadDirectories: string[];
    trashCleanupSettings: TrashCleanupSettings | null;
    setShowRenameModal: (value: boolean) => void;
    setShowPermissionsModal: (value: boolean) => void;
    setShowDeleteConfirm: (value: boolean) => void;
    setShowMoveToTrashConfirm: (value: boolean) => void;
    setShowUnarchiveConfirm: (value: boolean) => void;
    setShowCreateModal: (value: boolean) => void;
    setShowUploadPickerModal: (value: boolean) => void;
    setShowTrashBinModal: (value: boolean) => void;
    setShowTrashCleanupModal: (value: boolean) => void;
    setActionMode: (value: 'file' | 'folder') => void;
    setUploadMode: (value: 'device' | 'url') => void;
    setActionTargetDirectories: (paths: string[]) => void;
    handlePullComplete: () => Promise<void>;
    normalizeDirectory: (value: string) => string;
    joinDirectoryAndName: (directory: string, name: string) => string;
    submitDelete: () => void;
    submitMoveToTrash: () => void;
    submitUnarchive: () => void;
    submitCreateFile: (name: string, directory: string, content?: string) => Promise<void>;
    submitCreateFolder: (directory: string, name: string) => Promise<void>;
    handleUploadClick: () => void;
    uploadTargetRef: React.MutableRefObject<string[] | null>;
    onDirectoryLoad: (path: string) => Promise<unknown>;
    onFilesRestored: (paths: string[] | undefined) => Promise<void>;
    onSaveTrashCleanup: (values: { trash_cleanup_enabled: boolean; trash_retention_days: number; trash_retention_unit: 'days' | 'hours' }) => Promise<void>;
    clearAndAddHttpError: (error: Error) => void;
}

const FileTreeModals: React.FC<Props> = ({
    modalTargetPath,
    modalTargetMode,
    currentPath,
    showRenameModal,
    showPermissionsModal,
    showDeleteConfirm,
    showMoveToTrashConfirm,
    showUnarchiveConfirm,
    showCreateModal,
    showUploadPickerModal,
    showTrashBinModal,
    showTrashCleanupModal,
    actionMode,
    uploadMode,
    targetDirectories,
    uploadDirectories,
    trashCleanupSettings,
    setShowRenameModal,
    setShowPermissionsModal,
    setShowDeleteConfirm,
    setShowMoveToTrashConfirm,
    setShowUnarchiveConfirm,
    setShowCreateModal,
    setShowUploadPickerModal,
    setShowTrashBinModal,
    setShowTrashCleanupModal,
    setActionMode,
    setUploadMode,
    setActionTargetDirectories,
    handlePullComplete,
    normalizeDirectory,
    joinDirectoryAndName,
    submitDelete,
    submitMoveToTrash,
    submitUnarchive,
    submitCreateFile,
    submitCreateFolder,
    handleUploadClick,
    uploadTargetRef,
    onDirectoryLoad,
    onFilesRestored,
    onSaveTrashCleanup,
    clearAndAddHttpError,
}) => {
    const [selectedTemplate, setSelectedTemplate] = useState<FileTemplate | null>(null);
    const templates = getTemplates();

    return (
    <>
        <RenameModal
            visible={showRenameModal}
            onDismiss={() => setShowRenameModal(false)}
            file={modalTargetPath}
            onRenamed={async () => {
                const directory = modalTargetPath.substring(0, modalTargetPath.lastIndexOf('/')) || '/';
                await onDirectoryLoad(directory);
            }}
        />
        <PermissionsModal
            visible={showPermissionsModal}
            onDismiss={() => setShowPermissionsModal(false)}
            file={modalTargetPath}
            initialMode={modalTargetMode}
            onPermissionsChanged={async () => {
                const directory = modalTargetPath.substring(0, modalTargetPath.lastIndexOf('/')) || '/';
                await onDirectoryLoad(directory);
            }}
        />
        <Dialog.Confirm
            open={showDeleteConfirm}
            onClose={() => setShowDeleteConfirm(false)}
            title="Delete File"
            confirm="Delete"
            onConfirmed={submitDelete}
        >
            Are you sure you want to <strong>permanently delete</strong> <Code>{modalTargetPath}</Code>? This action cannot be undone. Consider using "Move to Trash" instead.
        </Dialog.Confirm>
        <Dialog.Confirm
            open={showMoveToTrashConfirm}
            onClose={() => setShowMoveToTrashConfirm(false)}
            title="Move to Trash"
            confirm="Move to Trash"
            onConfirmed={submitMoveToTrash}
        >
            Move <Code>{modalTargetPath}</Code> to trash? You can restore it later from the trash bin.
        </Dialog.Confirm>
        <Dialog.Confirm
            open={showUnarchiveConfirm}
            onClose={() => setShowUnarchiveConfirm(false)}
            title="Extract Archive"
            confirm="Extract"
            onConfirmed={submitUnarchive}
        >
            Extract <Code>{modalTargetPath.substring(modalTargetPath.lastIndexOf('/') + 1)}</Code> to the current directory? This may overwrite existing files.
        </Dialog.Confirm>
        <Dialog
            open={showCreateModal}
            onClose={() => { setShowCreateModal(false); setSelectedTemplate(null); }}
            title="Create"
        >
            <div onMouseDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()} className="betterfiles-scope">
                <div className="flex items-center gap-2 mb-4">
                    <Button
                        type="button"
                        onClick={() => setActionMode('file')}
                        size={Button.Sizes.Small}
                        variant={actionMode === 'file' ? Button.Variants.Primary : Button.Variants.Secondary}
                        aria-pressed={actionMode === 'file'}
                    >
                        New File
                    </Button>
                    <Button
                        type="button"
                        onClick={() => setActionMode('folder')}
                        size={Button.Sizes.Small}
                        variant={actionMode === 'folder' ? Button.Variants.Primary : Button.Variants.Secondary}
                        aria-pressed={actionMode === 'folder'}
                    >
                        New Folder
                    </Button>
                </div>
                {actionMode === 'file' && (
                    <div className='mb-4'>
                        <Label htmlFor="create-template">Template</Label>
                        <Select
                            id="create-template"
                            value={selectedTemplate?.id ?? ''}
                            onChange={(e) => {
                                const t = templates.find(t => t.id === e.target.value) || null;
                                setSelectedTemplate(t);
                            }}
                        >
                            <option value=''>Empty file</option>
                            {templates.map(t => (
                                <option key={t.id} value={t.id}>{t.name} ({t.filename})</option>
                            ))}
                        </Select>
                    </div>
                )}
                <Formik
                    enableReinitialize
                    initialValues={{
                        name: selectedTemplate?.filename ?? '',
                        directory: targetDirectories.length === 1 ? targetDirectories[0] : '',
                    }}
                    validationSchema={object().shape({
                        name: string().required(
                            actionMode === 'folder'
                                ? 'A folder name is required'
                                : 'A file name is required'
                        ),
                    })}
                    onSubmit={async (values, { setSubmitting }) => {
                        try {
                            if (actionMode === 'file') {
                                const customDirectory = values.directory?.trim();
                                const hasSingleTarget = targetDirectories.length === 1;
                                const targetList = hasSingleTarget ? [customDirectory || targetDirectories[0]] : targetDirectories;
                                const reloadDirs = new Set<string>();
                                for (const rawDir of targetList) {
                                    const directory = rawDir.startsWith('/') ? rawDir : `/${rawDir}`;
                                    await submitCreateFile(values.name, directory, selectedTemplate?.content);
                                    reloadDirs.add(directory);
                                }
                                if (!reloadDirs.has(currentPath)) reloadDirs.add(currentPath);
                                await Promise.all(Array.from(reloadDirs).map(dir => onDirectoryLoad(dir)));
                            } else {
                                const directoriesToUse =
                                    targetDirectories.length === 1
                                        ? [normalizeDirectory(values.directory || targetDirectories[0])]
                                        : targetDirectories.map(normalizeDirectory);
                                const reloadDirs = new Set<string>();
                                for (const directory of directoriesToUse) {
                                    await submitCreateFolder(directory, values.name);
                                    reloadDirs.add(directory);
                                }
                                if (!reloadDirs.has(currentPath)) reloadDirs.add(currentPath);
                                await Promise.all(Array.from(reloadDirs).map(dir => onDirectoryLoad(dir)));
                            }
                            setShowCreateModal(false);
                            setSelectedTemplate(null);
                            setActionTargetDirectories([]);
                        } catch (error) {
                            clearAndAddHttpError(error as Error);
                        } finally {
                            setSubmitting(false);
                        }
                    }}
                >
                    {({ submitForm, values, isSubmitting }) => (
                        <Form>
                            <Field
                                autoFocus
                                id="name"
                                name="name"
                                label={actionMode === 'folder' ? 'Folder Name' : 'File Name'}
                            />
                            {targetDirectories.length === 1 && (
                                <Field
                                    id="directory"
                                    name="directory"
                                    label="Directory (optional)"
                                    description={
                                        actionMode === 'folder'
                                            ? 'Override the target directory for this folder.'
                                            : 'Override the destination directory for this file.'
                                    }
                                    placeholder="/"
                                />
                            )}
                            {selectedTemplate && actionMode === 'file' && (
                                <div className='mt-3 rounded bg-neutral-800 border border-neutral-700 overflow-hidden'>
                                    <div className='px-3 py-1.5 border-b border-neutral-700'>
                                        <span className='text-xs text-neutral-500'>Preview</span>
                                    </div>
                                    <pre className='p-3 text-xs text-neutral-300 font-mono overflow-auto max-h-32 m-0'>
                                        {selectedTemplate.content || '(empty)'}
                                    </pre>
                                </div>
                            )}
                            {targetDirectories.length === 1 ? (
                                <p className="mt-2 text-sm text-neutral-400">
                                    Will be created at:{' '}
                                    <Code>
                                        {actionMode === 'folder'
                                            ? joinDirectoryAndName(values.directory || targetDirectories[0], values.name)
                                            : (() => {
                                                const directory = values.directory?.trim()
                                                    ? values.directory.trim().startsWith('/')
                                                        ? values.directory.trim()
                                                        : '/' + values.directory.trim()
                                                    : targetDirectories[0];
                                                return (directory || '/') + (values.name ? '/' + values.name : '');
                                            })()}
                                    </Code>
                                </p>
                            ) : (
                                <p className="mt-2 text-sm text-neutral-300">
                                    Will be created in <Code>{targetDirectories.length}</Code> directories.
                                </p>
                            )}
                            <Dialog.Footer>
                                <Button.Text onClick={() => { setShowCreateModal(false); setSelectedTemplate(null); }}>
                                    Cancel
                                </Button.Text>
                                <Button onClick={submitForm} disabled={isSubmitting}>
                                    {actionMode === 'folder' ? 'Create Folder' : 'Create File'}
                                </Button>
                            </Dialog.Footer>
                        </Form>
                    )}
                </Formik>
            </div>
        </Dialog>
        <Dialog
            open={showUploadPickerModal}
            onClose={() => setShowUploadPickerModal(false)}
            title="Upload"
        >
            <div onMouseDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()} className="betterfiles-scope">
                <div className="flex items-center gap-2 mb-4">
                    <Button
                        type="button"
                        onClick={() => setUploadMode('device')}
                        size={Button.Sizes.Small}
                        variant={uploadMode === 'device' ? Button.Variants.Primary : Button.Variants.Secondary}
                        aria-pressed={uploadMode === 'device'}
                    >
                        Device
                    </Button>
                    <Button
                        type="button"
                        onClick={() => setUploadMode('url')}
                        size={Button.Sizes.Small}
                        variant={uploadMode === 'url' ? Button.Variants.Primary : Button.Variants.Secondary}
                        aria-pressed={uploadMode === 'url'}
                    >
                        URL
                    </Button>
                </div>
                {uploadMode === 'device' ? (
                    <Formik
                        enableReinitialize
                        initialValues={{
                            directory: uploadDirectories.length === 1 ? uploadDirectories[0] : '',
                        }}
                        onSubmit={(values) => {
                            const customDirectory = values.directory?.trim();
                            const hasSingleTarget = uploadDirectories.length === 1;
                            const targetList = hasSingleTarget ? [customDirectory || uploadDirectories[0]] : uploadDirectories;
                            const normalizedTargets = targetList.map((rawDir) => normalizeDirectory(rawDir));
                            uploadTargetRef.current = normalizedTargets;
                            setShowUploadPickerModal(false);
                            handleUploadClick();
                        }}
                    >
                        {({ submitForm, values }) => (
                            <Form>
                                {uploadDirectories.length === 1 && (
                                    <Field
                                        id="directory"
                                        name="directory"
                                        label="Directory (optional)"
                                        description="Override the destination directory for this upload."
                                        placeholder="/"
                                    />
                                )}
                                {uploadDirectories.length === 1 ? (
                                    <p className="mt-2 text-sm text-neutral-300">
                                        Will upload to:{' '}
                                        <Code>
                                            {normalizeDirectory(values.directory || uploadDirectories[0])}
                                        </Code>
                                    </p>
                                ) : (
                                    <p className="mt-2 text-sm text-neutral-300">
                                        Will upload to <Code>{uploadDirectories.length}</Code> directories.
                                    </p>
                                )}
                                <Dialog.Footer>
                                    <Button.Text onClick={() => setShowUploadPickerModal(false)}>
                                        Cancel
                                    </Button.Text>
                                    <Button onClick={submitForm}>
                                        Choose Files
                                    </Button>
                                </Dialog.Footer>
                            </Form>
                        )}
                    </Formik>
                ) : (
                    <PullUrlInlineForm
                        directories={uploadDirectories}
                        onDismiss={() => setShowUploadPickerModal(false)}
                        onPullComplete={handlePullComplete}
                    />
                )}
            </div>
        </Dialog>
        <TrashBinModal
            visible={showTrashBinModal}
            onDismiss={() => setShowTrashBinModal(false)}
            onFilesRestored={onFilesRestored}
        />
        <TrashCleanupSettingsModal
            visible={showTrashCleanupModal}
            onDismiss={() => setShowTrashCleanupModal(false)}
            settings={trashCleanupSettings}
            onSave={onSaveTrashCleanup}
        />
    </>
    );
};

export default FileTreeModals;
