import { adminToast } from '@admin/components/ui/admin-toast';
import {
    DocumentBuilderPreview,
    buildLivePreviewDocument,
    type DocumentPreviewDocument,
} from '@admin/components/documents/document-builder-preview';
import { FormGroup } from '@admin/components/ui/forms/form-group';
import { FormSwitch } from '@admin/components/ui/forms/form-switch';
import { FileUploadInput } from '@admin/components/ui/forms/file-upload-input';
import {
    formControlClassName,
    formHelpClassName,
    formLabelClassName,
    primarySoftButtonClassName,
} from '@admin/components/ui/field-styles';
import { useFormResponse } from '@admin/hooks/use-form-response';
import { dashboardPersistentLayout } from '@admin/layouts/dashboard-page-layout';
import { DocumentBlockBuilder } from '@admin/pages/qr-codes/documentations/templates/document-block-builder';
import {
    DOCUMENT_DEFAULT_ACCENT,
    defaultBuilderBlocks,
    emptyDocumentLayout,
    brandingImagePreviewUrl,
    documentDefaultLogoUrl,
    documentDefaultThankYouUrl,
    DOCUMENT_RECOMMENDED_LOGO_HEIGHT,
    DOCUMENT_RECOMMENDED_LOGO_WIDTH,
    DOCUMENT_RECOMMENDED_THANK_YOU_HEIGHT,
    DOCUMENT_RECOMMENDED_THANK_YOU_WIDTH,
    type DocumentBlockTypeOption,
    type DocumentField,
    type DocumentLayoutConfig,
    type DocumentSelectOption,
} from '@admin/types/document';
import { Head, Link, useForm } from '@inertiajs/react';
import { FormEvent, useCallback, useDeferredValue, useMemo, useState } from 'react';

type BuilderTemplate = {
    id: number;
    parent_id: number | null;
    name: string;
    slug: string;
    kind: string;
    description: string | null;
    is_child: boolean;
    parent_name?: string | null;
    field_schema: DocumentField[];
    layout: DocumentLayoutConfig;
    child_editable_keys: string[];
    sort_order: number;
    status: boolean;
};

type BuilderPageProps = {
    template: BuilderTemplate;
    preview: DocumentPreviewDocument;
    block_type_options: DocumentBlockTypeOption[];
    style_options: DocumentSelectOption[];
    qr_position_options: DocumentSelectOption[];
    can_edit_blocks: boolean;
    can_edit_layout: boolean;
    editable_keys: string[] | null;
};

type BuilderFormData = {
    parent_id: string;
    name: string;
    slug: string;
    kind: string;
    description: string;
    field_schema: DocumentField[];
    layout: DocumentLayoutConfig;
    child_editable_keys: string[];
    sort_order: number;
    status: boolean;
};

function canEditKey(editableKeys: string[] | null, key: keyof DocumentLayoutConfig): boolean {
    if (editableKeys === null) {
        return true;
    }

    return editableKeys.includes(key);
}

function DocumentTemplateBuilder({
    template,
    preview,
    block_type_options: blockTypeOptions,
    can_edit_blocks: canEditBlocks,
    can_edit_layout: canEditLayout,
    editable_keys: editableKeys,
}: BuilderPageProps) {
    const initialLayout: DocumentLayoutConfig = {
        ...emptyDocumentLayout(),
        ...template.layout,
        style: 'builder',
        blocks: template.layout.blocks?.length ? template.layout.blocks : defaultBuilderBlocks(),
    };

    const [layout, setLayoutState] = useState<DocumentLayoutConfig>(initialLayout);
    const deferredLayout = useDeferredValue(layout);
    const previewPending = deferredLayout !== layout;

    const { setData, put, processing, errors, transform } = useForm<BuilderFormData>({
        parent_id: template.parent_id ? String(template.parent_id) : '',
        name: template.name,
        slug: template.slug,
        kind: template.kind,
        description: template.description ?? '',
        field_schema: template.field_schema,
        layout: initialLayout,
        child_editable_keys: template.child_editable_keys ?? [],
        sort_order: template.sort_order,
        status: template.status,
    });

    transform((formData) => ({
        ...formData,
        layout,
    }));

    const action = useFormResponse({ loadingMessage: 'Saving layout…' });

    const livePreview = useMemo(
        () => buildLivePreviewDocument(preview, deferredLayout),
        [preview, deferredLayout],
    );

    const setLayout = <K extends keyof DocumentLayoutConfig>(key: K, value: DocumentLayoutConfig[K]) => {
        setLayoutState((current) => ({ ...current, [key]: value }));
    };

    const handleBlocksChange = useCallback((blocks: DocumentLayoutConfig['blocks']) => {
        setLayoutState((current) => ({ ...current, blocks }));
    }, []);

    const handleSave = (event?: FormEvent) => {
        event?.preventDefault();

        setData('layout', layout);

        put(`/admin/api/update_document_template/${template.id}`, {
            onStart: action.onStart,
            onSuccess: action.onSuccess,
            onError: (formErrors) => {
                action.onError(formErrors);
                adminToast.error('Could not save layout. Check the highlighted fields.');
            },
            preserveScroll: true,
        });
    };

    return (
        <>
            <Head title={`Visual builder · ${template.name}`}>
                <link rel="preconnect" href="https://fonts.googleapis.com" />
                <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
                <link
                    href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:wght@400;500;700&display=swap"
                    rel="stylesheet"
                />
            </Head>

            <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
                <div>
                    <p className="text-sm text-textmuted">
                        <Link
                            href={route('admin.qr-codes.documentations.templates')}
                            className="text-primary hover:underline"
                        >
                            Templates
                        </Link>
                        <span className="mx-2">/</span>
                        Visual builder
                    </p>
                    <h1 className="text-xl font-semibold">{template.name}</h1>
                    <p className={formHelpClassName}>
                        Edit blocks on the left. The A4 preview on the right uses sample field values.
                        {template.is_child && template.parent_name
                            ? ` Child of ${template.parent_name}.`
                            : ''}
                    </p>
                </div>
                <div className="flex flex-wrap gap-2">
                    <Link
                        href={route('admin.qr-codes.documentations.templates')}
                        className={primarySoftButtonClassName}
                    >
                        Back to templates
                    </Link>
                    <button
                        type="button"
                        className="ti-btn ti-btn-primary"
                        disabled={processing || !canEditLayout}
                        onClick={() => handleSave()}
                    >
                        {processing ? 'Saving…' : 'Save layout'}
                    </button>
                </div>
            </div>

            <div className="document-builder-workspace grid gap-4 xl:grid-cols-[minmax(0,22rem)_minmax(0,1fr)]">
                <form className="box min-w-0" noValidate onSubmit={handleSave}>
                    <div className="box-header">
                        <h5 className="box-title">Layout</h5>
                    </div>
                    <div className="box-body space-y-4">
                        {canEditKey(editableKeys, 'title') && (
                            <FormGroup
                                label="Document title"
                                error={errors['layout.title']}
                                inputProps={{
                                    value: layout.title,
                                    required: true,
                                    onChange: (event) => setLayout('title', event.target.value),
                                }}
                            />
                        )}

                        {canEditKey(editableKeys, 'company_name') && (
                            <FormGroup
                                label="Company name"
                                error={errors['layout.company_name']}
                                inputProps={{
                                    value: layout.company_name,
                                    onChange: (event) => setLayout('company_name', event.target.value),
                                }}
                            />
                        )}

                        {canEditKey(editableKeys, 'header_contact') && (
                            <FormGroup
                                label="Header contact lines"
                                as="textarea"
                                helpText="One line per row."
                                error={errors['layout.header_contact']}
                                inputProps={{
                                    value: layout.header_contact,
                                    rows: 3,
                                    onChange: (event) => setLayout('header_contact', event.target.value),
                                }}
                            />
                        )}

                        {canEditKey(editableKeys, 'accent_color') && (
                            <FormGroup label="Accent colour" error={errors['layout.accent_color']}>
                                <div className="flex items-center gap-3">
                                    <input
                                        type="color"
                                        className="h-10 w-14 rounded-sm border border-defaultborder p-1"
                                        value={layout.accent_color || DOCUMENT_DEFAULT_ACCENT}
                                        onChange={(event) => setLayout('accent_color', event.target.value)}
                                    />
                                    <input
                                        className={formControlClassName}
                                        value={layout.accent_color}
                                        maxLength={7}
                                        onChange={(event) => setLayout('accent_color', event.target.value)}
                                    />
                                </div>
                            </FormGroup>
                        )}

                        {canEditKey(editableKeys, 'logo_path') && (
                            <FileUploadInput
                                label={`Logo (${DOCUMENT_RECOMMENDED_LOGO_WIDTH}×${DOCUMENT_RECOMMENDED_LOGO_HEIGHT} px recommended)`}
                                inputId="builder-layout-logo"
                                buttonText="Upload logo"
                                uploadUrl="/admin/api/document_template/upload_logo"
                                accept="image/png,image/jpeg,image/jpg,image/webp"
                                previewUrl={brandingImagePreviewUrl(
                                    layout.logo_path,
                                    layout.logo_url || preview.layout.logo_url || documentDefaultLogoUrl(),
                                )}
                                error={errors['layout.logo_path']}
                                helpText="Transparent PNG recommended. Leave empty to use the Chato Beach Resort logo."
                                onSuccess={(filename) => setLayout('logo_path', filename)}
                            />
                        )}

                        {canEditKey(editableKeys, 'thank_you_path') && (
                            <FileUploadInput
                                label={`Thank-you image (${DOCUMENT_RECOMMENDED_THANK_YOU_WIDTH}×${DOCUMENT_RECOMMENDED_THANK_YOU_HEIGHT} px recommended)`}
                                inputId="builder-layout-thank-you"
                                buttonText="Upload thank-you image"
                                uploadUrl="/admin/api/document_template/upload_thank_you"
                                accept="image/png,image/jpeg,image/jpg,image/webp"
                                previewUrl={brandingImagePreviewUrl(
                                    layout.thank_you_path,
                                    layout.thank_you_url || preview.layout.thank_you_url || documentDefaultThankYouUrl(),
                                )}
                                error={errors['layout.thank_you_path']}
                                helpText="Transparent PNG recommended. Leave empty to use the default thank-you image."
                                onSuccess={(filename) => setLayout('thank_you_path', filename)}
                            />
                        )}

                        {canEditKey(editableKeys, 'signature_image') && (
                            <FileUploadInput
                                label="Signature image"
                                inputId="builder-layout-signature"
                                buttonText="Upload signature"
                                uploadUrl="/admin/api/document_template/upload_signature"
                                accept="image/png,image/jpeg,image/jpg,image/webp"
                                previewUrl={brandingImagePreviewUrl(
                                    layout.signature_image,
                                    layout.signature_image_url || preview.layout.signature_image_url,
                                )}
                                error={errors['layout.signature_image']}
                                onSuccess={(filename) => setLayout('signature_image', filename)}
                            />
                        )}

                        {canEditKey(editableKeys, 'show_signature') && (
                            <FormSwitch
                                id="builder-show-signature"
                                label="Show signature line"
                                checked={layout.show_signature}
                                onChange={(event) => setLayout('show_signature', event.target.checked)}
                            />
                        )}

                        {canEditBlocks ? (
                            <DocumentBlockBuilder
                                blocks={layout.blocks ?? []}
                                fields={template.field_schema}
                                blockTypeOptions={blockTypeOptions}
                                onChange={handleBlocksChange}
                            />
                        ) : (
                            <p className={formHelpClassName}>
                                This child template cannot change layout blocks. Ask the parent template owner to allow
                                “Layout blocks”.
                            </p>
                        )}

                        <button type="submit" className="ti-btn ti-btn-primary w-full" disabled={processing || !canEditLayout}>
                            {processing ? 'Saving…' : 'Save layout'}
                        </button>
                    </div>
                </form>

                <div className="box min-w-0">
                    <div className="box-header flex flex-wrap items-center justify-between gap-2">
                        <div>
                            <h5 className="box-title">Live preview</h5>
                            <p className={formLabelClassName}>
                                {previewPending ? 'Updating preview…' : 'Sample data · updates as you edit'}
                            </p>
                        </div>
                        <span className="badge bg-primary/10 text-primary">A4</span>
                    </div>
                    <div
                        className={`box-body document-builder-preview-pane${previewPending ? ' opacity-80' : ''}`}
                    >
                        <DocumentBuilderPreview document={livePreview} />
                    </div>
                </div>
            </div>
        </>
    );
}

export default Object.assign(DocumentTemplateBuilder, {
    layout: dashboardPersistentLayout('Visual document builder', 'Compose blocks with a live A4 preview'),
});
