import React, { useCallback, useEffect, useState } from 'react';
import { Form, Formik } from 'formik';
import { boolean, number, object, string } from 'yup';
import { Button } from '@/components/elements/button/index';
import { Dialog } from '@/components/elements/dialog';
import Input, { Textarea } from '@/components/elements/Input';
import Select from '@/components/elements/Select';
import Spinner from '@/components/elements/Spinner';
import Switch from '@/components/elements/Switch';
import type { DateDisplayMode, TrashCleanupSettings, ViewMode } from '../types';

export interface FileTemplate {
    id: string;
    name: string;
    filename: string;
    content: string;
    builtin?: boolean;
}

const BUILTIN_TEMPLATES: FileTemplate[] = [
    { id: 'json', name: 'JSON', filename: 'config.json', content: '{\n    \n}\n', builtin: true },
    { id: 'yaml', name: 'YAML Config', filename: 'config.yml', content: '# Configuration\n\n', builtin: true },
    { id: 'env', name: 'Environment', filename: '.env', content: '# Environment Variables\n\n', builtin: true },
    {
        id: 'dockerfile',
        name: 'Dockerfile',
        filename: 'Dockerfile',
        content: 'FROM node:20-alpine\n\nWORKDIR /app\n\nCOPY . .\n\nRUN npm install\n\nCMD ["node", "index.js"]\n',
        builtin: true,
    },
    { id: 'shell', name: 'Shell Script', filename: 'script.sh', content: '#!/bin/bash\n\n', builtin: true },
    { id: 'python', name: 'Python', filename: 'main.py', content: '#!/usr/bin/env python3\n\n', builtin: true },
    {
        id: 'html',
        name: 'HTML',
        filename: 'index.html',
        content:
            '<!DOCTYPE html>\n<html lang="en">\n<head>\n    <meta charset="UTF-8">\n    <meta name="viewport" content="width=device-width, initial-scale=1.0">\n    <title>Page</title>\n</head>\n<body>\n    \n</body>\n</html>\n',
        builtin: true,
    },
];

export function getTemplates(): FileTemplate[] {
    try {
        const stored = localStorage.getItem('bfm-file-templates');
        const custom: FileTemplate[] = stored ? JSON.parse(stored) : [];
        return [...BUILTIN_TEMPLATES, ...custom];
    } catch {
        return [...BUILTIN_TEMPLATES];
    }
}

function saveCustomTemplates(templates: FileTemplate[]) {
    localStorage.setItem('bfm-file-templates', JSON.stringify(templates.filter((template) => !template.builtin)));
}

const BROWSE_DOUBLE_CLICK_DIRECTORIES_KEY = 'bfm-browse-double-click-directories';
const DESKTOP_FILE_CHECKBOXES_KEY = 'bfm-desktop-file-checkboxes';
const DESKTOP_FILE_CHECKBOXES_EVENT = 'bfm:desktop-file-checkboxes';

const getBrowseDoubleClickDirectories = () => (
    typeof window !== 'undefined' && localStorage.getItem(BROWSE_DOUBLE_CLICK_DIRECTORIES_KEY) === 'true'
);

const getDesktopFileCheckboxes = () => (
    typeof window === 'undefined' || localStorage.getItem(DESKTOP_FILE_CHECKBOXES_KEY) !== 'false'
);

interface SettingsDialogProps {
    open: boolean;
    onClose: () => void;
    viewMode: ViewMode;
    onViewModeChange: (mode: ViewMode) => void;
    dateDisplayMode: DateDisplayMode;
    onDateDisplayModeChange: (mode: DateDisplayMode) => void;
    canConfigureTrash: boolean;
    trashCleanupSettings: TrashCleanupSettings | null;
    onSaveTrashSettings: (settings: TrashCleanupSettings) => Promise<void>;
}

interface SectionProps {
    title: string;
    description?: string;
    children: React.ReactNode;
}

const Section: React.FC<SectionProps> = ({ title, description, children }) => (
    <section className='border-t border-neutral-700 pt-5 first:border-t-0 first:pt-0'>
        <div className='mb-4'>
            <h3 className='text-base font-semibold text-neutral-100'>{title}</h3>
            {description && <p className='mt-1 text-sm text-neutral-400'>{description}</p>}
        </div>
        {children}
    </section>
);

interface SwitchRowProps {
    fieldName: string;
    title: string;
    description: string;
    defaultChecked: boolean;
    onChange: () => void;
}

const SwitchRow: React.FC<SwitchRowProps> = ({ fieldName, title, description, defaultChecked, onChange }) => (
    <div className='flex items-center gap-4 rounded bg-neutral-700 border border-neutral-800 p-4 shadow-inner'>
        <Switch name={fieldName} defaultChecked={defaultChecked} onChange={onChange} />
        <div className='min-w-0'>
            <p className='text-sm font-semibold text-neutral-200'>{title}</p>
            <p className='mt-1 text-sm text-neutral-400'>{description}</p>
        </div>
    </div>
);

const TemplatesSection: React.FC = () => {
    const [templates, setTemplates] = useState(getTemplates);
    const [editing, setEditing] = useState<FileTemplate | null>(null);
    const [adding, setAdding] = useState(false);
    const [newName, setNewName] = useState('');
    const [newFilename, setNewFilename] = useState('');
    const [newContent, setNewContent] = useState('');

    const refresh = useCallback(() => setTemplates(getTemplates()), []);
    const customTemplates = templates.filter((template) => !template.builtin);

    const handleAdd = () => {
        if (!newName.trim() || !newFilename.trim()) return;

        saveCustomTemplates([
            ...customTemplates,
            {
                id: `custom-${Date.now()}`,
                name: newName.trim(),
                filename: newFilename.trim(),
                content: newContent,
            },
        ]);

        setAdding(false);
        setNewName('');
        setNewFilename('');
        setNewContent('');
        refresh();
    };

    const handleDelete = (id: string) => {
        saveCustomTemplates(customTemplates.filter((template) => template.id !== id));
        refresh();
    };

    const handleExport = () => {
        if (customTemplates.length === 0) return;

        const blob = new Blob([JSON.stringify(customTemplates, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const anchor = document.createElement('a');
        anchor.href = url;
        anchor.download = 'bfm-templates.json';
        anchor.click();
        URL.revokeObjectURL(url);
    };

    const handleImport = () => {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';
        input.onchange = async (event) => {
            const file = (event.target as HTMLInputElement).files?.[0];
            if (!file) return;

            try {
                const text = await file.text();
                const imported: FileTemplate[] = JSON.parse(text);
                if (!Array.isArray(imported)) return;

                const merged = [...customTemplates];
                for (const template of imported) {
                    if (!template.name || !template.filename) continue;
                    if (merged.some((existing) => existing.id === template.id)) continue;

                    merged.push({
                        ...template,
                        id: template.id || `custom-${Date.now()}-${Math.random().toString(36).slice(2)}`,
                        builtin: false,
                    });
                }

                saveCustomTemplates(merged);
                refresh();
            } catch {
                // Invalid imports are ignored so the dialog does not trap the user in a failed file picker flow.
            }
        };
        input.click();
    };

    const handleSaveEdit = () => {
        if (!editing || !editing.name.trim() || !editing.filename.trim()) return;

        saveCustomTemplates(customTemplates.map((template) => (template.id === editing.id ? editing : template)));
        setEditing(null);
        refresh();
    };

    return (
        <Section
            title='File templates'
            description='Templates appear when creating a new file. Add your common config files here so you do not start from an empty editor.'
        >
            <div className='mb-4 flex flex-wrap items-center gap-2'>
                <Button.Text type='button' size={Button.Sizes.Small} onClick={handleExport} disabled={customTemplates.length === 0}>
                    Export
                </Button.Text>
                <Button.Text type='button' size={Button.Sizes.Small} onClick={handleImport}>
                    Import
                </Button.Text>
                <Button type='button' size={Button.Sizes.Small} onClick={() => {
                    setAdding((value) => !value);
                    setEditing(null);
                }}>
                    {adding ? 'Cancel' : 'Add template'}
                </Button>
            </div>

            {adding && (
                <div className='mb-4 rounded bg-neutral-700 border border-neutral-800 p-4 shadow-inner'>
                    <div className='grid grid-cols-1 gap-4 md:grid-cols-2'>
                        <div>
                            <label htmlFor='new_template_name' className='mb-2 block text-sm font-semibold text-neutral-200'>Template name</label>
                            <Input
                                id='new_template_name'
                                type='text'
                                placeholder='My Template'
                                value={newName}
                                onChange={(event: React.ChangeEvent<HTMLInputElement>) => setNewName(event.target.value)}
                            />
                        </div>
                        <div>
                            <label htmlFor='new_template_filename' className='mb-2 block text-sm font-semibold text-neutral-200'>Default filename</label>
                            <Input
                                id='new_template_filename'
                                type='text'
                                placeholder='config.yml'
                                value={newFilename}
                                onChange={(event: React.ChangeEvent<HTMLInputElement>) => setNewFilename(event.target.value)}
                            />
                        </div>
                    </div>
                    <div className='mt-4'>
                        <label htmlFor='new_template_content' className='mb-2 block text-sm font-semibold text-neutral-200'>Content</label>
                        <Textarea
                            id='new_template_content'
                            rows={5}
                            placeholder='Template content'
                            value={newContent}
                            onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => setNewContent(event.target.value)}
                            className='font-mono'
                        />
                    </div>
                    <div className='mt-4 flex justify-end'>
                        <Button type='button' size={Button.Sizes.Small} onClick={handleAdd} disabled={!newName.trim() || !newFilename.trim()}>
                            Save template
                        </Button>
                    </div>
                </div>
            )}

            {editing && (
                <div className='mb-4 rounded bg-neutral-700 border border-neutral-800 p-4 shadow-inner'>
                    <div className='grid grid-cols-1 gap-4 md:grid-cols-2'>
                        <div>
                            <label htmlFor='edit_template_name' className='mb-2 block text-sm font-semibold text-neutral-200'>Template name</label>
                            <Input
                                id='edit_template_name'
                                type='text'
                                value={editing.name}
                                onChange={(event: React.ChangeEvent<HTMLInputElement>) => setEditing({ ...editing, name: event.target.value })}
                            />
                        </div>
                        <div>
                            <label htmlFor='edit_template_filename' className='mb-2 block text-sm font-semibold text-neutral-200'>Default filename</label>
                            <Input
                                id='edit_template_filename'
                                type='text'
                                value={editing.filename}
                                onChange={(event: React.ChangeEvent<HTMLInputElement>) => setEditing({ ...editing, filename: event.target.value })}
                            />
                        </div>
                    </div>
                    <div className='mt-4'>
                        <label htmlFor='edit_template_content' className='mb-2 block text-sm font-semibold text-neutral-200'>Content</label>
                        <Textarea
                            id='edit_template_content'
                            rows={5}
                            value={editing.content}
                            onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => setEditing({ ...editing, content: event.target.value })}
                            className='font-mono'
                        />
                    </div>
                    <div className='mt-4 flex justify-end gap-2'>
                        <Button.Text type='button' size={Button.Sizes.Small} onClick={() => setEditing(null)}>
                            Cancel
                        </Button.Text>
                        <Button type='button' size={Button.Sizes.Small} onClick={handleSaveEdit} disabled={!editing.name.trim() || !editing.filename.trim()}>
                            Save changes
                        </Button>
                    </div>
                </div>
            )}

            <div className='max-h-56 overflow-y-auto'>
                {templates.map((template) => (
                    <div key={template.id} className='flex items-center justify-between gap-3 border-t border-neutral-700 py-3 first:border-t-0'>
                        <div className='min-w-0'>
                            <p className='truncate text-sm font-semibold text-neutral-200'>{template.name}</p>
                            <p className='truncate text-sm text-neutral-400'>{template.filename}</p>
                        </div>
                        {!template.builtin && (
                            <div className='flex shrink-0 items-center gap-2'>
                                <Button.Text
                                    type='button'
                                    size={Button.Sizes.Small}
                                    onClick={() => {
                                        setEditing(template);
                                        setAdding(false);
                                    }}
                                >
                                    Edit
                                </Button.Text>
                                <Button.Danger type='button' size={Button.Sizes.Small} onClick={() => handleDelete(template.id)}>
                                    Delete
                                </Button.Danger>
                            </div>
                        )}
                    </div>
                ))}
            </div>
        </Section>
    );
};

export const SettingsDialog: React.FC<SettingsDialogProps> = ({
    open,
    onClose,
    viewMode,
    onViewModeChange,
    dateDisplayMode,
    onDateDisplayModeChange,
    canConfigureTrash,
    trashCleanupSettings,
    onSaveTrashSettings,
}) => {
    const [browseDoubleClickDirectories, setBrowseDoubleClickDirectories] = useState(getBrowseDoubleClickDirectories);
    const [desktopFileCheckboxes, setDesktopFileCheckboxes] = useState(getDesktopFileCheckboxes);
    const [isMobileViewport, setIsMobileViewport] = useState(false);
    const viewModes: Array<{ key: ViewMode; label: string }> = [
        { key: 'tree', label: 'Tree' },
        { key: 'browse', label: 'Browse' },
    ];
    const dateDisplayModes: Array<{ key: DateDisplayMode; label: string; description: string }> = [
        { key: 'relative', label: 'Relative', description: 'Shows now, 12m, 4h, or 6d.' },
        { key: 'absolute', label: 'Date', description: 'Shows fixed dates like 2026-05-14 20:30.' },
    ];

    useEffect(() => {
        if (typeof window === 'undefined') return;
        const checkMobile = () => setIsMobileViewport(window.innerWidth < 768);
        checkMobile();
        window.addEventListener('resize', checkMobile);
        return () => window.removeEventListener('resize', checkMobile);
    }, []);

    return (
        <Dialog open={open} onClose={onClose} title='File Manager Settings'>
            <div className='space-y-6'>
                <Section title='View mode' description='Choose how files and folders are shown in the sidebar.'>
                    <div className='grid grid-cols-1 gap-2 sm:grid-cols-2'>
                        {viewModes.map((mode) => {
                            const active = viewMode === mode.key;

                            return active ? (
                                <Button key={mode.key} type='button' onClick={() => onViewModeChange(mode.key)} className='w-full'>
                                    {mode.label}
                                </Button>
                            ) : (
                                <Button.Text
                                    key={mode.key}
                                    type='button'
                                    variant={Button.Variants.Secondary}
                                    onClick={() => onViewModeChange(mode.key)}
                                    className='w-full'
                                >
                                    {mode.label}
                                </Button.Text>
                            );
                        })}
                    </div>

                    {viewMode === 'browse' && (
                        <div className='mt-4'>
                            <SwitchRow
                                fieldName='browse_double_click_directories'
                                title='Double click folders to open'
                                description='When this is on, one click selects a folder and double click opens it.'
                                defaultChecked={browseDoubleClickDirectories}
                                onChange={() => {
                                    const next = !browseDoubleClickDirectories;
                                    setBrowseDoubleClickDirectories(next);
                                    localStorage.setItem(BROWSE_DOUBLE_CLICK_DIRECTORIES_KEY, next.toString());
                                    window.dispatchEvent(new CustomEvent('bfm:browse-double-click-directories', {
                                        detail: { enabled: next },
                                    }));
                                }}
                            />
                        </div>
                    )}
                </Section>

                {!isMobileViewport && (
                    <Section title='Selection' description='Control how multiple files are selected on desktop.'>
                        <SwitchRow
                            fieldName='desktop_file_checkboxes'
                            title='Enable file checkboxes'
                            description='Show checkboxes beside files and folders for easier multi-select.'
                            defaultChecked={desktopFileCheckboxes}
                            onChange={() => {
                                const next = !desktopFileCheckboxes;
                                setDesktopFileCheckboxes(next);
                                localStorage.setItem(DESKTOP_FILE_CHECKBOXES_KEY, next.toString());
                                window.dispatchEvent(new CustomEvent(DESKTOP_FILE_CHECKBOXES_EVENT, {
                                    detail: { enabled: next },
                                }));
                                try {
                                    window.dispatchEvent(new StorageEvent('storage', {
                                        key: DESKTOP_FILE_CHECKBOXES_KEY,
                                        newValue: next.toString(),
                                    }));
                                } catch {}
                            }}
                        />
                    </Section>
                )}

                <Section title='File list' description='Choose how file metadata is shown in the explorer.'>
                    <div className='grid grid-cols-1 gap-2 sm:grid-cols-2'>
                        {dateDisplayModes.map((mode) => {
                            const active = dateDisplayMode === mode.key;

                            return active ? (
                                <Button key={mode.key} type='button' onClick={() => onDateDisplayModeChange(mode.key)} className='w-full justify-start text-left'>
                                    <span>
                                        <span className='block'>{mode.label}</span>
                                        <span className='block text-xs font-normal text-blue-100/80'>{mode.description}</span>
                                    </span>
                                </Button>
                            ) : (
                                <Button.Text
                                    key={mode.key}
                                    type='button'
                                    variant={Button.Variants.Secondary}
                                    onClick={() => onDateDisplayModeChange(mode.key)}
                                    className='w-full justify-start text-left'
                                >
                                    <span>
                                        <span className='block'>{mode.label}</span>
                                        <span className='block text-xs text-neutral-500'>{mode.description}</span>
                                    </span>
                                </Button.Text>
                            );
                        })}
                    </div>
                </Section>

                <Section title='Editor' description='Control how the text editor helps while you type.'>
                    <SwitchRow
                        fieldName='live_autocomplete'
                        title='Live autocomplete'
                        description='Show suggestions as you type. Ctrl+Space still opens suggestions when this is off.'
                        defaultChecked={localStorage.getItem('bfm-live-autocomplete') !== 'false'}
                        onChange={() => {
                            const current = localStorage.getItem('bfm-live-autocomplete') !== 'false';
                            const next = !current;
                            localStorage.setItem('bfm-live-autocomplete', next.toString());
                            window.dispatchEvent(new CustomEvent('bfm:autocomplete-toggle', { detail: { enabled: next } }));
                        }}
                    />
                </Section>

                <Section title='Drag and drop' description='Choose whether dropping files into folders asks for confirmation first.'>
                    <SwitchRow
                        fieldName='drag_confirm'
                        title='Confirm before moving files'
                        description='When this is off, files move immediately when they are dropped.'
                        defaultChecked={localStorage.getItem('bfm-drag-confirm-enabled') !== 'false'}
                        onChange={() => {
                            const current = localStorage.getItem('bfm-drag-confirm-enabled') !== 'false';
                            localStorage.setItem('bfm-drag-confirm-enabled', (!current).toString());
                        }}
                    />
                </Section>

                <TemplatesSection />

                {canConfigureTrash && (
                    <Section title='Trash cleanup' description='Automatically delete old items from the trash after the time you choose.'>
                        {!trashCleanupSettings ? (
                            <div className='flex items-center justify-center py-6 text-neutral-300'>
                                <Spinner size='small' />
                                <span className='ml-2 text-sm'>Loading settings...</span>
                            </div>
                        ) : (
                            <Formik
                                enableReinitialize
                                initialValues={{
                                    trash_cleanup_enabled: trashCleanupSettings.trash_cleanup_enabled ?? false,
                                    trash_retention_days: trashCleanupSettings.trash_retention_days ?? 30,
                                    trash_retention_unit: trashCleanupSettings.trash_retention_unit ?? 'days',
                                }}
                                validationSchema={object().shape({
                                    trash_cleanup_enabled: boolean().required(),
                                    trash_retention_days: number().required().integer().min(1),
                                    trash_retention_unit: string().required().oneOf(['days', 'hours']),
                                })}
                                onSubmit={async (values, { setSubmitting }) => {
                                    try {
                                        await onSaveTrashSettings({
                                            trash_cleanup_enabled: values.trash_cleanup_enabled,
                                            trash_retention_days: Number(values.trash_retention_days),
                                            trash_retention_unit: values.trash_retention_unit as 'days' | 'hours',
                                        });
                                    } finally {
                                        setSubmitting(false);
                                    }
                                }}
                            >
                                {({ dirty, isSubmitting, setFieldValue, submitForm, values }) => (
                                    <Form>
                                        <div className='space-y-4'>
                                            <SwitchRow
                                                fieldName='trash_cleanup_enabled'
                                                title='Enable automatic trash cleanup'
                                                description='Old trash items will be deleted without another prompt.'
                                                defaultChecked={values.trash_cleanup_enabled}
                                                onChange={() => setFieldValue('trash_cleanup_enabled', !values.trash_cleanup_enabled)}
                                            />
                                            <div className='grid grid-cols-1 gap-4 md:grid-cols-2'>
                                                <div>
                                                    <label htmlFor='trash_retention_days' className='mb-2 block text-sm font-semibold text-neutral-200'>Delete items older than</label>
                                                    <Input
                                                        id='trash_retention_days'
                                                        name='trash_retention_days'
                                                        type='number'
                                                        min={1}
                                                        value={values.trash_retention_days}
                                                        onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
                                                            setFieldValue('trash_retention_days', event.target.value)
                                                        }
                                                    />
                                                </div>
                                                <div>
                                                    <label htmlFor='trash_retention_unit' className='mb-2 block text-sm font-semibold text-neutral-200'>Unit</label>
                                                    <Select
                                                        id='trash_retention_unit'
                                                        name='trash_retention_unit'
                                                        value={values.trash_retention_unit}
                                                        onChange={(event) => setFieldValue('trash_retention_unit', event.currentTarget.value)}
                                                    >
                                                        <option value='hours'>Hours</option>
                                                        <option value='days'>Days</option>
                                                    </Select>
                                                </div>
                                            </div>
                                            <div className='flex justify-end'>
                                                <Button type='button' onClick={submitForm} disabled={isSubmitting || !dirty}>
                                                    {isSubmitting ? 'Saving...' : 'Save trash cleanup'}
                                                </Button>
                                            </div>
                                        </div>
                                    </Form>
                                )}
                            </Formik>
                        )}
                    </Section>
                )}
            </div>
        </Dialog>
    );
};
