import { Button, Field } from '@/Components/ui';
import { csrfHeaders } from '@/admin/settings/types';
import type { TestimonialsSection } from '@/marketing/cms-types';
import { Loader2, Trash2, Upload } from 'lucide-react';
import { useRef, useState } from 'react';
import { HEADLINE_EDITOR_PREVIEW, ItemList, LabeledRichText, RowTools } from './shared';

type Item = TestimonialsSection['items'][number];

type Props = {
    value: TestimonialsSection;
    onChange: (next: TestimonialsSection) => void;
    errors?: Record<string, string>;
};

function blankItem(): Item {
    return { text: '', name: '', role: '', image: '' };
}

export default function TestimonialsEditor({ value, onChange, errors }: Props) {
    const e = errors ?? {};

    return (
        <div className="space-y-4">
            <Field
                id={`${value.id}-eyebrow`}
                label="Eyebrow"
                value={value.eyebrow ?? ''}
                onChange={(ev) => onChange({ ...value, eyebrow: ev.target.value })}
                placeholder="Optional badge label (e.g. Features)"
                error={e.eyebrow}
                hint="Plain text — uppercase pill above the heading. Leave blank to hide."
                labelClassName="text-[11px] font-medium"
            />
            <LabeledRichText
                id={`${value.id}-heading`}
                label="Heading"
                value={value.heading ?? ''}
                onChange={(html) => onChange({ ...value, heading: html })}
                error={e.heading}
                hint="Italicize the accent phrase via the toolbar. Block formatting is stripped on render."
                minHeight={70}
                            editorClassName={HEADLINE_EDITOR_PREVIEW}
            />
            <LabeledRichText
                id={`${value.id}-subhead`}
                label="Subhead (optional)"
                value={value.subhead ?? ''}
                onChange={(v) => onChange({ ...value, subhead: v })}
                error={e.subhead}
            />

            <div>
                <p className="mb-2 text-[11px] font-medium text-foreground">Testimonials</p>
                <p className="mb-3 text-[12px] text-muted-foreground">
                    Section auto-hides when the list is empty (avoids shipping fake testimonials).
                </p>
                <ItemList<Item>
                    items={value.items}
                    onChange={(items) => onChange({ ...value, items })}
                    blank={blankItem}
                    addLabel="Add testimonial"
                    emptyLabel="No testimonials yet."
                    confirmDelete={(it) =>
                        `Delete testimonial from "${it.name?.trim() || 'unnamed'}"?`
                    }
                    renderRow={(item, idx, h) => {
                        const itemErr = (k: string) => e[`items.${idx}.${k}`];
                        return (
                            <div
                                key={`${value.id}-tm-${idx}`}
                                className="rounded-lg border border-border bg-background/40 p-3"
                            >
                                <div className="flex justify-end">
                                    <RowTools
                                        idx={idx}
                                        count={value.items.length}
                                        onMove={h.move}
                                        onRemove={h.remove}
                                        moveLabel="testimonial"
                                        removeLabel="testimonial"
                                    />
                                </div>
                                <div className="mt-2 space-y-3">
                                    <LabeledRichText
                                        id={`${value.id}-tm-${idx}-text`}
                                        label="Quote"
                                        value={item.text ?? ''}
                                        onChange={(v) => h.update({ text: v })}
                                        error={itemErr('text')}
                                    />
                                    <div className="grid gap-3 sm:grid-cols-2">
                                        <Field
                                            id={`${value.id}-tm-${idx}-name`}
                                            label="Name"
                                            value={item.name ?? ''}
                                            onChange={(ev) => h.update({ name: ev.target.value })}
                                            error={itemErr('name')}
                                            placeholder="Jane Doe"
                                        />
                                        <Field
                                            id={`${value.id}-tm-${idx}-role`}
                                            label="Role"
                                            value={item.role ?? ''}
                                            onChange={(ev) => h.update({ role: ev.target.value })}
                                            error={itemErr('role')}
                                            placeholder="Indie developer"
                                        />
                                    </div>
                                    <AvatarUpload
                                        idPrefix={`${value.id}-tm-${idx}`}
                                        image={item.image}
                                        imageUrl={item.imageUrl}
                                        onChange={(image, imageUrl) =>
                                            h.update({ image, imageUrl })
                                        }
                                        error={itemErr('image')}
                                    />
                                </div>
                            </div>
                        );
                    }}
                />
            </div>
        </div>
    );
}

/* Avatar upload widget — mirrors HeroEditor's image upload but smaller
 * footprint for the per-row avatar. Posts to /admin/marketing/testimonial-avatar
 * (max 2 MB). Server returns `{ path, url }`; we store the storage path
 * as `image` plus the resolved `imageUrl` for instant preview without
 * waiting for a save round-trip. Backward-compatible: admins can still
 * paste a URL or `/public/...` path into the secondary text input
 * (hidden by default; revealed via "Use a URL instead"). */
function AvatarUpload({
    idPrefix,
    image,
    imageUrl,
    onChange,
    error,
}: {
    idPrefix: string;
    image?: string;
    imageUrl?: string;
    onChange: (image: string | undefined, imageUrl: string | undefined) => void;
    error?: string;
}) {
    const fileInputRef = useRef<HTMLInputElement | null>(null);
    const [uploading, setUploading] = useState(false);
    const [uploadError, setUploadError] = useState<string | null>(null);
    const [urlMode, setUrlMode] = useState(false);

    // Preview source: imageUrl (server-resolved storage path) wins, falls
    // back to image directly (URL or /public path). Same logic as the
    // public renderer.
    const previewSrc = imageUrl || image || '';
    const hasAvatar = previewSrc !== '';

    const onPickFile = async (file: File) => {
        setUploading(true);
        setUploadError(null);
        try {
            const fd = new FormData();
            fd.append('file', file);
            const headers = csrfHeaders();
            delete (headers as Record<string, string>)['Content-Type'];
            const res = await fetch('/admin/marketing/testimonial-avatar', {
                method: 'POST',
                credentials: 'same-origin',
                headers,
                body: fd,
            });
            if (res.status === 422) {
                const body = await res.json().catch(() => null);
                setUploadError(body?.errors?.file?.[0] ?? body?.message ?? 'Upload failed (validation).');
                return;
            }
            if (!res.ok) {
                setUploadError(`Upload failed (${res.status}).`);
                return;
            }
            const body = (await res.json()) as { path: string; url: string };
            onChange(body.path, body.url);
        } catch {
            setUploadError('Network error during upload.');
        } finally {
            setUploading(false);
            if (fileInputRef.current) fileInputRef.current.value = '';
        }
    };

    const clear = () => onChange(undefined, undefined);

    return (
        <div className="space-y-1.5">
            <label className="block text-[11px] font-medium text-foreground">
                Avatar
            </label>
            <div className="flex items-start gap-3 rounded-lg border border-border bg-background p-3">
                {hasAvatar ? (
                    <img
                        src={previewSrc}
                        alt=""
                        className="h-12 w-12 shrink-0 rounded-full border border-border object-cover"
                    />
                ) : (
                    <div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-full border border-dashed border-border bg-muted/40 text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
                        none
                    </div>
                )}
                <div className="flex flex-1 flex-col gap-2">
                    <div className="flex flex-wrap items-center gap-2">
                        <Button
                            type="button"
                            variant="secondary"
                            size="sm"
                            onClick={() => fileInputRef.current?.click()}
                            disabled={uploading}
                            data-testid={`${idPrefix}-avatar-upload`}
                        >
                            {uploading ? (
                                <Loader2 className="h-3.5 w-3.5 animate-spin" />
                            ) : (
                                <Upload className="h-3.5 w-3.5" />
                            )}
                            {uploading ? 'Uploading…' : hasAvatar ? 'Replace' : 'Upload image'}
                        </Button>
                        {hasAvatar && (
                            <Button
                                type="button"
                                variant="secondary"
                                size="sm"
                                onClick={clear}
                                disabled={uploading}
                                data-testid={`${idPrefix}-avatar-remove`}
                            >
                                <Trash2 className="h-3.5 w-3.5" />
                                Remove
                            </Button>
                        )}
                        <button
                            type="button"
                            onClick={() => setUrlMode((v) => !v)}
                            className="text-[11px] font-medium text-muted-foreground hover:text-accent"
                        >
                            {urlMode ? 'Hide URL field' : 'Use a URL instead'}
                        </button>
                    </div>
                    {urlMode && (
                        <Field
                            id={`${idPrefix}-avatar-url`}
                            label=""
                            value={image ?? ''}
                            onChange={(ev) => onChange(ev.target.value || undefined, undefined)}
                            placeholder="https://yoursite.com/avatar.jpg"
                            hint="External URL or /public path. Use Upload above for files you want stored on the active disk."
                        />
                    )}
                </div>
                <input
                    ref={fileInputRef}
                    type="file"
                    accept="image/jpeg,image/png,image/webp"
                    className="hidden"
                    onChange={(ev) => {
                        const f = ev.target.files?.[0];
                        if (f) onPickFile(f);
                    }}
                />
            </div>
            {uploadError && (
                <p className="text-xs text-destructive" role="alert">{uploadError}</p>
            )}
            {error && !uploadError && (
                <p className="text-xs text-destructive">{error}</p>
            )}
        </div>
    );
}
