'use client';

import { useState } from 'react';
import type { StoreSiteBlock } from '@alqove/api-client';
import { blockKey } from '@/components/storefront/block-key';
import { Field, inputCls, SecondaryButton, Toggle } from './ui';

type BlockData = Record<string, unknown>;

export interface BlockTypeMeta {
  type: NonNullable<StoreSiteBlock['type']>;
  label: string;
  description: string;
  /** Seeded when the seller adds the block, so it renders immediately. */
  defaults: BlockData;
}

export const BLOCK_TYPES: BlockTypeMeta[] = [
  {
    type: 'hero',
    label: 'Hero banner',
    description: 'Full-width headline with an optional background image and button.',
    defaults: { headline: 'Welcome', align: 'center', overlay: true },
  },
  {
    type: 'products',
    label: 'Product grid',
    description: 'Live listings from your store — never a stale copy.',
    defaults: { heading: 'New arrivals', source: 'newest', limit: 8, show_view_all: true },
  },
  {
    type: 'rich_text',
    label: 'Text',
    description: 'A heading and paragraphs. Blank lines start a new paragraph.',
    defaults: { heading: 'About us', body: '' },
  },
  {
    type: 'hours',
    label: 'Opening hours',
    description: 'Your store hours, edited once under Details.',
    defaults: { heading: 'Hours' },
  },
  {
    type: 'map',
    label: 'Address & directions',
    description: 'Your address with a "Get directions" button.',
    defaults: { heading: 'Find us', show_directions_link: true },
  },
  {
    type: 'contact',
    label: 'Contact',
    description: 'Email, phone and a link back to your Alqove store.',
    defaults: { heading: 'Get in touch', show_email: true, show_phone: true, show_message_link: true },
  },
  {
    type: 'gallery',
    label: 'Image gallery',
    description: 'A grid of photos of the shop or a lookbook.',
    defaults: { images: [] },
  },
  {
    type: 'faq',
    label: 'FAQ',
    description: 'Question and answer pairs in an accordion.',
    defaults: { heading: 'Frequently asked', items: [{ question: '', answer: '' }] },
  },
  {
    type: 'cta',
    label: 'Call to action',
    description: 'A coloured band with one prominent button.',
    defaults: { headline: '', label: '', href: '/' },
  },
  {
    type: 'divider',
    label: 'Divider',
    description: 'A horizontal rule between sections.',
    defaults: {},
  },
];

export function blockLabel(type: string | undefined): string {
  return BLOCK_TYPES.find((b) => b.type === type)?.label ?? (type ?? 'Block');
}

export function newBlock(meta: BlockTypeMeta): StoreSiteBlock {
  return {
    // The API assigns the persisted id; this one only has to be unique in the
    // editor until the page is saved.
    id: `new-${Math.random().toString(36).slice(2, 10)}`,
    type: meta.type,
    data: structuredClone(meta.defaults),
  };
}

interface BlockListProps {
  blocks: StoreSiteBlock[];
  onChange: (blocks: StoreSiteBlock[]) => void;
}

export function BlockList({ blocks, onChange }: BlockListProps) {
  function move(index: number, delta: number) {
    const target = index + delta;
    if (target < 0 || target >= blocks.length) return;
    const next = [...blocks];
    [next[index], next[target]] = [next[target], next[index]];
    onChange(next);
  }

  function update(index: number, data: BlockData) {
    const next = [...blocks];
    next[index] = { ...next[index], data };
    onChange(next);
  }

  function remove(index: number) {
    onChange(blocks.filter((_, i) => i !== index));
  }

  if (blocks.length === 0) {
    return (
      <p className="rounded border border-dashed border-forest/25 px-4 py-8 text-center text-sm text-ink/60">
        This page has no sections yet. Add one below.
      </p>
    );
  }

  return (
    <ul className="space-y-3">
      {blocks.map((block, index) => (
        <li key={blockKey(block, index)}>
          <BlockCard
            block={block}
            index={index}
            total={blocks.length}
            onMoveUp={() => move(index, -1)}
            onMoveDown={() => move(index, 1)}
            onRemove={() => remove(index)}
            onChange={(data) => update(index, data)}
          />
        </li>
      ))}
    </ul>
  );
}

interface BlockCardProps {
  block: StoreSiteBlock;
  index: number;
  total: number;
  onMoveUp: () => void;
  onMoveDown: () => void;
  onRemove: () => void;
  onChange: (data: BlockData) => void;
}

function BlockCard({
  block,
  index,
  total,
  onMoveUp,
  onMoveDown,
  onRemove,
  onChange,
}: BlockCardProps) {
  const [open, setOpen] = useState(false);
  const label = blockLabel(block.type);

  return (
    <div className="rounded border border-forest/20 bg-white">
      <div className="flex items-center gap-2 px-3 py-2">
        <button
          type="button"
          onClick={() => setOpen((v) => !v)}
          aria-expanded={open}
          className="flex-1 text-left text-sm font-medium text-ink"
        >
          <span className="mr-2 text-ink/40">{index + 1}.</span>
          {label}
        </button>
        <SecondaryButton
          onClick={onMoveUp}
          disabled={index === 0}
          ariaLabel={`Move ${label} up`}
          title="Move up"
        >
          ↑
        </SecondaryButton>
        <SecondaryButton
          onClick={onMoveDown}
          disabled={index === total - 1}
          ariaLabel={`Move ${label} down`}
          title="Move down"
        >
          ↓
        </SecondaryButton>
        <button
          type="button"
          onClick={() => {
            if (confirm(`Remove the ${label} section?`)) onRemove();
          }}
          className="rounded px-2 py-1.5 text-sm text-terracotta hover:underline"
        >
          Remove
        </button>
      </div>

      {open && (
        <div className="border-t border-forest/10 px-3 py-4">
          <BlockFields block={block} onChange={onChange} />
        </div>
      )}
    </div>
  );
}

function text(data: BlockData, key: string): string {
  const value = data[key];
  return typeof value === 'string' ? value : '';
}

function flag(data: BlockData, key: string, fallback = false): boolean {
  const value = data[key];
  return typeof value === 'boolean' ? value : fallback;
}

function BlockFields({
  block,
  onChange,
}: {
  block: StoreSiteBlock;
  onChange: (data: BlockData) => void;
}) {
  const data = (block.data ?? {}) as BlockData;
  const set = (patch: BlockData) => onChange({ ...data, ...patch });

  switch (block.type) {
    case 'hero':
      return (
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="Headline">
            <input
              className={inputCls}
              value={text(data, 'headline')}
              onChange={(e) => set({ headline: e.target.value })}
            />
          </Field>
          <Field label="Sub-headline">
            <input
              className={inputCls}
              value={text(data, 'subhead')}
              onChange={(e) => set({ subhead: e.target.value || undefined })}
            />
          </Field>
          <Field label="Background image URL" hint="Leave blank for a plain background.">
            <input
              className={inputCls}
              placeholder="https://…"
              value={text(data, 'image_url')}
              onChange={(e) => set({ image_url: e.target.value || undefined })}
            />
          </Field>
          <Field label="Alignment">
            <select
              className={inputCls}
              value={text(data, 'align') || 'center'}
              onChange={(e) => set({ align: e.target.value })}
            >
              <option value="center">Centered</option>
              <option value="left">Left</option>
            </select>
          </Field>
          <Field label="Button label">
            <input
              className={inputCls}
              value={text(data, 'cta_label')}
              onChange={(e) => set({ cta_label: e.target.value || undefined })}
            />
          </Field>
          <Field label="Button link" hint="e.g. #products, /about, or a full URL.">
            <input
              className={inputCls}
              value={text(data, 'cta_href')}
              onChange={(e) => set({ cta_href: e.target.value || undefined })}
            />
          </Field>
          <div className="sm:col-span-2">
            <Toggle
              checked={flag(data, 'overlay', true)}
              onChange={(v) => set({ overlay: v })}
              label="Darken the image so the text stays readable"
            />
          </div>
        </div>
      );

    case 'products': {
      const source = text(data, 'source') || 'newest';
      const ids = Array.isArray(data.item_ids) ? (data.item_ids as string[]) : [];
      return (
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="Heading">
            <input
              className={inputCls}
              value={text(data, 'heading')}
              onChange={(e) => set({ heading: e.target.value || undefined })}
            />
          </Field>
          <Field label="Which items">
            <select
              className={inputCls}
              value={source}
              onChange={(e) => set({ source: e.target.value })}
            >
              <option value="newest">Newest listings</option>
              <option value="category">A category</option>
              <option value="picked">Specific items</option>
            </select>
          </Field>
          {source === 'category' && (
            <Field label="Category slug" hint="As it appears in your Alqove browse URLs.">
              <input
                className={inputCls}
                value={text(data, 'category_slug')}
                onChange={(e) => set({ category_slug: e.target.value })}
              />
            </Field>
          )}
          {source === 'picked' && (
            <Field label="Item IDs" hint="One per line. Sold or removed items are skipped.">
              <textarea
                rows={4}
                className={inputCls}
                value={ids.join('\n')}
                onChange={(e) =>
                  set({
                    item_ids: e.target.value
                      .split('\n')
                      .map((v) => v.trim())
                      .filter(Boolean),
                  })
                }
              />
            </Field>
          )}
          <Field label="How many (1–24)">
            <input
              className={inputCls}
              inputMode="numeric"
              value={String(typeof data.limit === 'number' ? data.limit : 8)}
              onChange={(e) => {
                const n = Number(e.target.value.replace(/\D/g, ''));
                set({ limit: Math.max(1, Math.min(24, n || 1)) });
              }}
            />
          </Field>
          <div className="sm:col-span-2">
            <Toggle
              checked={flag(data, 'show_view_all', true)}
              onChange={(v) => set({ show_view_all: v })}
              label='Show a "View all" link to your full Alqove catalogue'
            />
          </div>
        </div>
      );
    }

    case 'rich_text':
      return (
        <div className="space-y-3">
          <Field label="Heading">
            <input
              className={inputCls}
              value={text(data, 'heading')}
              onChange={(e) => set({ heading: e.target.value || undefined })}
            />
          </Field>
          <Field label="Body" hint="Plain text. A blank line starts a new paragraph.">
            <textarea
              rows={8}
              className={inputCls}
              value={text(data, 'body')}
              onChange={(e) => set({ body: e.target.value })}
            />
          </Field>
          <Field label="Alignment">
            <select
              className={inputCls}
              value={text(data, 'align') || 'left'}
              onChange={(e) => set({ align: e.target.value })}
            >
              <option value="left">Left</option>
              <option value="center">Centered</option>
            </select>
          </Field>
        </div>
      );

    case 'hours':
      return (
        <div className="space-y-3">
          <Field label="Heading">
            <input
              className={inputCls}
              value={text(data, 'heading')}
              onChange={(e) => set({ heading: e.target.value || undefined })}
            />
          </Field>
          <Field label="Note" hint="Holiday closures, appointment-only days, and so on.">
            <textarea
              rows={2}
              className={inputCls}
              value={text(data, 'note')}
              onChange={(e) => set({ note: e.target.value || undefined })}
            />
          </Field>
          <p className="text-xs text-ink/50">
            The times themselves are set once under the Details tab.
          </p>
        </div>
      );

    case 'map':
      return (
        <div className="space-y-3">
          <Field label="Heading">
            <input
              className={inputCls}
              value={text(data, 'heading')}
              onChange={(e) => set({ heading: e.target.value || undefined })}
            />
          </Field>
          <Field
            label="Address override"
            hint="Leave blank to use your store's ship-from address."
          >
            <input
              className={inputCls}
              value={text(data, 'address_override')}
              onChange={(e) => set({ address_override: e.target.value || undefined })}
            />
          </Field>
          <Field label="Parking / entrance note">
            <textarea
              rows={2}
              className={inputCls}
              value={text(data, 'note')}
              onChange={(e) => set({ note: e.target.value || undefined })}
            />
          </Field>
          <Toggle
            checked={flag(data, 'show_directions_link', true)}
            onChange={(v) => set({ show_directions_link: v })}
            label='Show a "Get directions" button'
          />
        </div>
      );

    case 'contact':
      return (
        <div className="space-y-3">
          <Field label="Heading">
            <input
              className={inputCls}
              value={text(data, 'heading')}
              onChange={(e) => set({ heading: e.target.value || undefined })}
            />
          </Field>
          <Field label="Intro text">
            <textarea
              rows={2}
              className={inputCls}
              value={text(data, 'body')}
              onChange={(e) => set({ body: e.target.value || undefined })}
            />
          </Field>
          <Toggle
            checked={flag(data, 'show_email', true)}
            onChange={(v) => set({ show_email: v })}
            label="Show contact email"
          />
          <Toggle
            checked={flag(data, 'show_phone', true)}
            onChange={(v) => set({ show_phone: v })}
            label="Show contact phone"
          />
          <Toggle
            checked={flag(data, 'show_message_link', true)}
            onChange={(v) => set({ show_message_link: v })}
            label="Link to your Alqove store page"
          />
        </div>
      );

    case 'gallery': {
      const images = Array.isArray(data.images)
        ? (data.images as { url?: string; alt?: string }[])
        : [];
      const setImages = (next: { url?: string; alt?: string }[]) => set({ images: next });

      return (
        <div className="space-y-3">
          <Field label="Heading">
            <input
              className={inputCls}
              value={text(data, 'heading')}
              onChange={(e) => set({ heading: e.target.value || undefined })}
            />
          </Field>
          {images.map((image, i) => (
            <div key={i} className="grid gap-2 sm:grid-cols-[2fr_1fr_auto]">
              <input
                className={inputCls}
                placeholder="https://…"
                value={image.url ?? ''}
                onChange={(e) =>
                  setImages(images.map((im, j) => (i === j ? { ...im, url: e.target.value } : im)))
                }
              />
              <input
                className={inputCls}
                placeholder="Alt text"
                value={image.alt ?? ''}
                onChange={(e) =>
                  setImages(images.map((im, j) => (i === j ? { ...im, alt: e.target.value } : im)))
                }
              />
              <SecondaryButton onClick={() => setImages(images.filter((_, j) => j !== i))}>
                Remove
              </SecondaryButton>
            </div>
          ))}
          <SecondaryButton
            onClick={() => setImages([...images, { url: '', alt: '' }])}
            disabled={images.length >= 12}
          >
            + Add image
          </SecondaryButton>
        </div>
      );
    }

    case 'faq': {
      const items = Array.isArray(data.items)
        ? (data.items as { question?: string; answer?: string }[])
        : [];
      const setItems = (next: { question?: string; answer?: string }[]) => set({ items: next });

      return (
        <div className="space-y-4">
          <Field label="Heading">
            <input
              className={inputCls}
              value={text(data, 'heading')}
              onChange={(e) => set({ heading: e.target.value || undefined })}
            />
          </Field>
          {items.map((item, i) => (
            <div key={i} className="space-y-2 rounded border border-forest/15 p-3">
              <input
                className={inputCls}
                placeholder="Question"
                value={item.question ?? ''}
                onChange={(e) =>
                  setItems(items.map((it, j) => (i === j ? { ...it, question: e.target.value } : it)))
                }
              />
              <textarea
                rows={3}
                className={inputCls}
                placeholder="Answer"
                value={item.answer ?? ''}
                onChange={(e) =>
                  setItems(items.map((it, j) => (i === j ? { ...it, answer: e.target.value } : it)))
                }
              />
              <SecondaryButton onClick={() => setItems(items.filter((_, j) => j !== i))}>
                Remove question
              </SecondaryButton>
            </div>
          ))}
          <SecondaryButton
            onClick={() => setItems([...items, { question: '', answer: '' }])}
            disabled={items.length >= 20}
          >
            + Add question
          </SecondaryButton>
        </div>
      );
    }

    case 'cta':
      return (
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="Headline">
            <input
              className={inputCls}
              value={text(data, 'headline')}
              onChange={(e) => set({ headline: e.target.value })}
            />
          </Field>
          <Field label="Button label">
            <input
              className={inputCls}
              value={text(data, 'label')}
              onChange={(e) => set({ label: e.target.value })}
            />
          </Field>
          <Field label="Button link">
            <input
              className={inputCls}
              value={text(data, 'href')}
              onChange={(e) => set({ href: e.target.value })}
            />
          </Field>
          <Field label="Background colour" hint="Leave blank to use your theme colour.">
            <input
              type="color"
              className={inputCls}
              value={text(data, 'background') || '#065f46'}
              onChange={(e) => set({ background: e.target.value })}
            />
          </Field>
          <div className="sm:col-span-2">
            <Field label="Supporting text">
              <textarea
                rows={2}
                className={inputCls}
                value={text(data, 'body')}
                onChange={(e) => set({ body: e.target.value || undefined })}
              />
            </Field>
          </div>
        </div>
      );

    case 'divider':
      return <p className="text-sm text-ink/60">Nothing to configure.</p>;

    default:
      return (
        <p className="text-sm text-ink/60">
          This section type isn&apos;t editable in this version of the dashboard.
        </p>
      );
  }
}
