import { Head, Link, useForm } from '@inertiajs/react';
import { useRef } from 'react';

import { Switch } from '@/components/ui/switch';
import { AdminLayout } from '@/layouts/admin-layout';

type Option = {
    id: number;
    name: string;
};

type StatusOption = {
    value: 'draft' | 'published';
    label: string;
};

type ContentFontOption = {
    value: 'sans' | 'serif' | 'technical';
    label: string;
};

export type BlogArticleMedia = {
    id: number;
    url: string;
    mime_type: string | null;
    original_name: string | null;
    is_image: boolean;
};

export type BlogArticleForm = {
    blog_category_id: string;
    user_id: string;
    title: string;
    slug: string;
    excerpt: string;
    body: string;
    status: 'draft' | 'published';
    content_font: 'sans' | 'serif' | 'technical';
    seo_title: string;
    meta_description: string;
    published_at: string;
    tag_ids: number[];
    new_media: File[];
    remove_media_ids: number[];
};

type BlogArticleCreateProps = {
    categoryOptions: Option[];
    tagOptions: Option[];
    authorOptions: Option[];
    statusOptions: StatusOption[];
    contentFontOptions: ContentFontOption[];
    defaultAuthorId: number | null;
};

export default function BlogArticleCreate({
    categoryOptions,
    tagOptions,
    authorOptions,
    statusOptions,
    contentFontOptions,
    defaultAuthorId,
}: BlogArticleCreateProps) {
    const form = useForm<BlogArticleForm>({
        blog_category_id: '',
        user_id: defaultAuthorId ? String(defaultAuthorId) : '',
        title: '',
        slug: '',
        excerpt: '',
        body: '',
        status: 'draft',
        content_font: 'sans',
        seo_title: '',
        meta_description: '',
        published_at: '',
        tag_ids: [],
        new_media: [],
        remove_media_ids: [],
    });

    const submit = (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();

        form.transform(transformArticleForm);
        form.post('/admin/blog-articles', { forceFormData: true });
    };

    return (
        <AdminLayout>
            <Head title="Create Blog Article" />

            <BlogArticleFormView
                title="Create Blog Article"
                form={form}
                categoryOptions={categoryOptions}
                tagOptions={tagOptions}
                authorOptions={authorOptions}
                statusOptions={statusOptions}
                contentFontOptions={contentFontOptions}
                existingMedia={[]}
                onSubmit={submit}
            />
        </AdminLayout>
    );
}

type FormViewProps = {
    title: string;
    form: ReturnType<typeof useForm<BlogArticleForm>>;
    categoryOptions: Option[];
    tagOptions: Option[];
    authorOptions: Option[];
    statusOptions: StatusOption[];
    contentFontOptions: ContentFontOption[];
    existingMedia: BlogArticleMedia[];
    onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
};

export function BlogArticleFormView({
    title,
    form,
    categoryOptions,
    tagOptions,
    authorOptions,
    statusOptions,
    contentFontOptions,
    existingMedia,
    onSubmit,
}: FormViewProps) {
    const bodyRef = useRef<HTMLTextAreaElement | null>(null);

    const toggleTag = (tagId: number, checked: boolean) => {
        if (checked) {
            form.setData(
                'tag_ids',
                Array.from(new Set([...form.data.tag_ids, tagId])),
            );

            return;
        }

        form.setData(
            'tag_ids',
            form.data.tag_ids.filter((id) => id !== tagId),
        );
    };

    const toggleRemoveMedia = (mediaId: number, checked: boolean) => {
        if (checked) {
            form.setData(
                'remove_media_ids',
                Array.from(new Set([...form.data.remove_media_ids, mediaId])),
            );

            return;
        }

        form.setData(
            'remove_media_ids',
            form.data.remove_media_ids.filter((id) => id !== mediaId),
        );
    };

    const insertBlock = (text: string) => {
        const textarea = bodyRef.current;

        if (textarea === null) {
            form.setData('body', `${form.data.body}\n${text}`);

            return;
        }

        const start = textarea.selectionStart;
        const end = textarea.selectionEnd;
        const before = form.data.body.slice(0, start);
        const after = form.data.body.slice(end);
        const spacerBefore = before.endsWith('\n') || before === '' ? '' : '\n';
        const spacerAfter = after.startsWith('\n') || after === '' ? '' : '\n';
        const nextBody = `${before}${spacerBefore}${text}${spacerAfter}${after}`;

        form.setData('body', nextBody);

        window.requestAnimationFrame(() => {
            textarea.focus();
            textarea.setSelectionRange(
                start + spacerBefore.length + text.length,
                start + spacerBefore.length + text.length,
            );
        });
    };

    const wrapSelection = (
        prefix: string,
        suffix: string,
        fallback: string,
    ) => {
        const textarea = bodyRef.current;

        if (textarea === null) {
            form.setData(
                'body',
                `${form.data.body}${prefix}${fallback}${suffix}`,
            );

            return;
        }

        const start = textarea.selectionStart;
        const end = textarea.selectionEnd;
        const selected = form.data.body.slice(start, end) || fallback;
        const nextBody = `${form.data.body.slice(0, start)}${prefix}${selected}${suffix}${form.data.body.slice(end)}`;

        form.setData('body', nextBody);

        window.requestAnimationFrame(() => {
            textarea.focus();
            textarea.setSelectionRange(
                start + prefix.length,
                start + prefix.length + selected.length,
            );
        });
    };

    return (
        <div className="space-y-5">
            <div className="flex flex-wrap items-center justify-between gap-3">
                <h1 className="text-2xl font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                    {title}
                </h1>
                <Link
                    href="/admin/blog-articles"
                    className="text-sm font-medium text-slate-600 hover:text-[#0a1530] dark:text-[#d7c7ff] dark:hover:text-[#efe8ff]"
                >
                    Back to list
                </Link>
            </div>

            <form onSubmit={onSubmit} className="space-y-4">
                <div className="grid gap-4 md:grid-cols-2">
                    <Field label="Title" error={form.errors.title}>
                        <input
                            value={form.data.title}
                            onChange={(event) =>
                                form.setData('title', event.target.value)
                            }
                            required
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        />
                    </Field>
                    <Field label="Slug" error={form.errors.slug}>
                        <input
                            value={form.data.slug}
                            onChange={(event) =>
                                form.setData('slug', event.target.value)
                            }
                            placeholder="Optional"
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        />
                    </Field>
                </div>

                <div className="grid gap-4 md:grid-cols-5">
                    <Field
                        label="Category"
                        error={form.errors.blog_category_id}
                    >
                        <select
                            value={form.data.blog_category_id}
                            onChange={(event) =>
                                form.setData(
                                    'blog_category_id',
                                    event.target.value,
                                )
                            }
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        >
                            <option value="">Uncategorized</option>
                            {categoryOptions.map((option) => (
                                <option key={option.id} value={option.id}>
                                    {option.name}
                                </option>
                            ))}
                        </select>
                    </Field>
                    <Field label="Author" error={form.errors.user_id}>
                        <select
                            value={form.data.user_id}
                            onChange={(event) =>
                                form.setData('user_id', event.target.value)
                            }
                            required
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        >
                            <option value="">Select author</option>
                            {authorOptions.map((option) => (
                                <option key={option.id} value={option.id}>
                                    {option.name}
                                </option>
                            ))}
                        </select>
                    </Field>
                    <Field label="Status" error={form.errors.status}>
                        <select
                            value={form.data.status}
                            onChange={(event) =>
                                form.setData(
                                    'status',
                                    event.target
                                        .value as BlogArticleForm['status'],
                                )
                            }
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        >
                            {statusOptions.map((option) => (
                                <option key={option.value} value={option.value}>
                                    {option.label}
                                </option>
                            ))}
                        </select>
                    </Field>
                    <Field label="Font" error={form.errors.content_font}>
                        <select
                            value={form.data.content_font}
                            onChange={(event) =>
                                form.setData(
                                    'content_font',
                                    event.target
                                        .value as BlogArticleForm['content_font'],
                                )
                            }
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        >
                            {contentFontOptions.map((option) => (
                                <option key={option.value} value={option.value}>
                                    {option.label}
                                </option>
                            ))}
                        </select>
                    </Field>
                    <Field label="Publish At" error={form.errors.published_at}>
                        <input
                            type="datetime-local"
                            value={form.data.published_at}
                            onChange={(event) =>
                                form.setData('published_at', event.target.value)
                            }
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        />
                    </Field>
                </div>

                <Field label="Excerpt" error={form.errors.excerpt}>
                    <textarea
                        value={form.data.excerpt}
                        onChange={(event) =>
                            form.setData('excerpt', event.target.value)
                        }
                        className="h-24 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                    />
                </Field>

                <Field label="Media Files" error={form.errors.new_media}>
                    <input
                        type="file"
                        multiple
                        accept="image/jpeg,image/png,image/webp,image/gif,video/mp4,video/webm"
                        onChange={(event) => {
                            const files = event.target.files
                                ? Array.from(event.target.files)
                                : [];
                            form.setData('new_media', files);
                        }}
                        className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff]"
                    />
                    {form.errors['new_media.0'] ? (
                        <p className="mt-1 text-xs text-rose-600">
                            {form.errors['new_media.0']}
                        </p>
                    ) : null}
                </Field>

                {existingMedia.length > 0 ? (
                    <div className="space-y-3">
                        <p className="text-sm font-medium text-[#0a1530] dark:text-[#e5dcff]">
                            Existing Media
                        </p>
                        <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
                            {existingMedia.map((media) => {
                                const isMarked =
                                    form.data.remove_media_ids.includes(
                                        media.id,
                                    );

                                return (
                                    <div
                                        key={media.id}
                                        className="rounded-xl border border-slate-200 p-3 dark:border-[#3c2b68]"
                                    >
                                        {media.is_image ? (
                                            <img
                                                src={media.url}
                                                alt={
                                                    media.original_name ||
                                                    `Blog media ${media.id}`
                                                }
                                                className="h-32 w-full rounded-lg object-cover"
                                            />
                                        ) : (
                                            <video
                                                src={media.url}
                                                controls
                                                className="h-32 w-full rounded-lg object-cover"
                                            />
                                        )}
                                        <p className="mt-2 truncate text-xs text-slate-600 dark:text-[#c7bde8]">
                                            {media.original_name ||
                                                `Media ${media.id}`}
                                        </p>
                                        <div className="mt-3 flex flex-wrap items-center gap-2">
                                            <button
                                                type="button"
                                                onClick={() =>
                                                    insertBlock(
                                                        `[media:${media.id}]`,
                                                    )
                                                }
                                                className="rounded-md border border-slate-300 px-2.5 py-1 text-xs font-medium text-slate-700 hover:bg-slate-100 dark:border-[#4a3a78] dark:text-[#e5dcff] dark:hover:bg-[#2a1d50]"
                                            >
                                                Insert
                                            </button>
                                            <div className="inline-flex items-center gap-2 text-xs text-rose-700 dark:text-rose-300">
                                                <Switch
                                                    checked={isMarked}
                                                    onChange={(checked) =>
                                                        toggleRemoveMedia(
                                                            media.id,
                                                            checked,
                                                        )
                                                    }
                                                    ariaLabel={`Remove blog media ${media.id} on save`}
                                                />
                                                Remove
                                            </div>
                                        </div>
                                    </div>
                                );
                            })}
                        </div>
                    </div>
                ) : null}

                <Field label="Body" error={form.errors.body}>
                    <div className="mb-2 flex flex-wrap gap-2">
                        <EditorButton
                            onClick={() => insertBlock('## Section heading')}
                        >
                            H2
                        </EditorButton>
                        <EditorButton
                            onClick={() => insertBlock('### Detail heading')}
                        >
                            H3
                        </EditorButton>
                        <EditorButton
                            onClick={() =>
                                wrapSelection('**', '**', 'bold text')
                            }
                        >
                            Bold
                        </EditorButton>
                        <EditorButton
                            onClick={() =>
                                wrapSelection('*', '*', 'italic text')
                            }
                        >
                            Italic
                        </EditorButton>
                        <EditorButton
                            onClick={() => insertBlock('> Important note')}
                        >
                            Quote
                        </EditorButton>
                        <EditorButton
                            onClick={() => insertBlock('- List item')}
                        >
                            List
                        </EditorButton>
                    </div>
                    <textarea
                        ref={bodyRef}
                        value={form.data.body}
                        onChange={(event) =>
                            form.setData('body', event.target.value)
                        }
                        required
                        className="h-80 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                    />
                </Field>

                {tagOptions.length > 0 ? (
                    <div className="space-y-2">
                        <p className="text-sm font-medium text-[#0a1530] dark:text-[#e5dcff]">
                            Tags
                        </p>
                        <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
                            {tagOptions.map((tag) => (
                                <label
                                    key={tag.id}
                                    className="flex items-center gap-2 rounded-lg border border-slate-200 px-3 py-2 text-sm text-[#0a1530] dark:border-[#3c2b68] dark:text-[#e5dcff]"
                                >
                                    <input
                                        type="checkbox"
                                        checked={form.data.tag_ids.includes(
                                            tag.id,
                                        )}
                                        onChange={(event) =>
                                            toggleTag(
                                                tag.id,
                                                event.target.checked,
                                            )
                                        }
                                    />
                                    {tag.name}
                                </label>
                            ))}
                        </div>
                    </div>
                ) : null}

                <div className="grid gap-4 md:grid-cols-2">
                    <Field label="SEO Title" error={form.errors.seo_title}>
                        <input
                            value={form.data.seo_title}
                            onChange={(event) =>
                                form.setData('seo_title', event.target.value)
                            }
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        />
                    </Field>
                    <Field
                        label="Meta Description"
                        error={form.errors.meta_description}
                    >
                        <textarea
                            value={form.data.meta_description}
                            onChange={(event) =>
                                form.setData(
                                    'meta_description',
                                    event.target.value,
                                )
                            }
                            className="h-20 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        />
                    </Field>
                </div>

                <button
                    type="submit"
                    disabled={form.processing}
                    className="rounded-lg bg-[#0b7285] px-4 py-2 text-sm font-semibold text-white hover:bg-[#095f6f] disabled:opacity-50 dark:bg-[#7c3aed] dark:hover:bg-[#8b5cf6]"
                >
                    Save Article
                </button>
            </form>
        </div>
    );
}

export function transformArticleForm(data: BlogArticleForm) {
    return {
        ...data,
        blog_category_id:
            data.blog_category_id === '' ? null : Number(data.blog_category_id),
        user_id: Number(data.user_id),
        slug: data.slug === '' ? null : data.slug,
        excerpt: data.excerpt === '' ? null : data.excerpt,
        seo_title: data.seo_title === '' ? null : data.seo_title,
        meta_description:
            data.meta_description === '' ? null : data.meta_description,
        published_at: data.published_at === '' ? null : data.published_at,
    };
}

function EditorButton({
    onClick,
    children,
}: {
    onClick: () => void;
    children: React.ReactNode;
}) {
    return (
        <button
            type="button"
            onClick={onClick}
            className="rounded-md border border-slate-300 px-2.5 py-1 text-xs font-medium text-slate-700 hover:bg-slate-100 dark:border-[#4a3a78] dark:text-[#e5dcff] dark:hover:bg-[#2a1d50]"
        >
            {children}
        </button>
    );
}

function Field({
    label,
    error,
    children,
}: {
    label: string;
    error?: string;
    children: React.ReactNode;
}) {
    return (
        <div>
            <label className="block text-sm font-medium text-[#0a1530] dark:text-[#e5dcff]">
                {label}
            </label>
            <div className="mt-1">{children}</div>
            {error ? (
                <p className="mt-1 text-xs text-rose-600">{error}</p>
            ) : null}
        </div>
    );
}
