import { useCallback, useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import Layout from '../components/Layout';
import CardFrame, { CardPreview, DEFAULT_LAYOUT } from '../components/designer/CardFrame';
import ZoneEditor from '../components/designer/ZoneEditor';
import { FRAMES, RARITIES, getFrame } from '../components/designer/frames';
import { EXISTING_GAMES } from '../lib/designer-games.js';
import { PALETTE_SLOTS } from '../lib/frame-palette.js';
import { Button } from '../components/ui';
import { useAuth } from '../lib/use-auth';

const BLANK_DESIGN = {
  id: null,
  name: '',
  mana_cost: '',
  card_type: '',
  rarity: 'common',
  rules_text: '',
  actions: '',
  flavor_quote: '',
  power: '',
  toughness: '',
  frame_id: 'classic',
  artwork_url: '',
  art_mode: 'framed',
  game_target: 'custom',
  custom_game_id: null,
  custom_frame_id: null,
};

const BLANK_PALETTE = Object.fromEntries(
  PALETTE_SLOTS.map(({ key }) => [key, getFrame('classic').palette[key]])
);

export default function Designer() {
  const router = useRouter();
  const { user, loading: authLoading } = useAuth();

  const [design, setDesign] = useState(BLANK_DESIGN);
  const [saving, setSaving] = useState(false);
  const [exporting, setExporting] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [message, setMessage] = useState(null);

  // Custom games for targeting
  const [games, setGames] = useState([]);
  const [newGameName, setNewGameName] = useState('');
  const [creatingGame, setCreatingGame] = useState(false);

  // Custom frames + symbols
  const [frames, setFrames] = useState([]);
  const [symbols, setSymbols] = useState([]);
  const [frameEditor, setFrameEditor] = useState(null); // { id, name, palette } | null
  const [savingFrame, setSavingFrame] = useState(false);
  const [symbolCode, setSymbolCode] = useState('');
  const symbolFileRef = useRef(null);
  const [uploadingSymbol, setUploadingSymbol] = useState(false);
  const [uploadingTexture, setUploadingTexture] = useState(false);
  const textureFileRef = useRef(null);
  const [uploadingFrameImage, setUploadingFrameImage] = useState(false);
  const frameImageFileRef = useRef(null);

  const cardRef = useRef(null);
  const fileInputRef = useRef(null);

  const authHeaders = useCallback(() => {
    const token = localStorage.getItem('auth_token');
    return token ? { Authorization: `Bearer ${token}` } : {};
  }, []);

  const loadGames = useCallback(async () => {
    try {
      const response = await fetch('/api/custom-games', { headers: authHeaders() });
      if (response.ok) {
        const data = await response.json();
        setGames(data.games);
      }
    } catch {
      // Non-fatal — designer works without custom games.
    }
  }, [authHeaders]);

  const loadFrames = useCallback(async () => {
    try {
      const response = await fetch('/api/custom-frames', { headers: authHeaders() });
      if (response.ok) {
        const data = await response.json();
        setFrames(data.frames);
      }
    } catch {
      // Non-fatal — starter frames still work.
    }
  }, [authHeaders]);

  const loadSymbols = useCallback(async () => {
    try {
      const response = await fetch('/api/custom-symbols', { headers: authHeaders() });
      if (response.ok) {
        const data = await response.json();
        setSymbols(data.symbols);
      }
    } catch {
      // Non-fatal — text pips still work.
    }
  }, [authHeaders]);

  useEffect(() => {
    if (user) {
      loadGames(); // eslint-disable-line react-hooks/set-state-in-effect -- fetch-driven reload via async loadGames
      loadFrames();
      loadSymbols();
    }
  }, [user, loadGames, loadFrames, loadSymbols]);

  const handleCreateGame = async () => {
    const name = newGameName.trim();
    if (!name) return;
    setCreatingGame(true);
    try {
      const response = await fetch('/api/custom-games', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...authHeaders() },
        body: JSON.stringify({ name }),
      });
      const data = await response.json();
      if (response.ok) {
        setGames((prev) => [...prev, data.game]);
        setDesign((prev) => ({
          ...prev,
          game_target: 'custom',
          custom_game_id: data.game.id,
        }));
        setNewGameName('');
        setMessage({ kind: 'success', text: `Game "${data.game.name}" created.` });
      } else {
        setMessage({ kind: 'error', text: data.error || 'Could not create game.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Could not create game.' });
    } finally {
      setCreatingGame(false);
    }
  };

  const openNewFrameEditor = () => {
    const base = getFrame(design.frame_id).palette;
    setFrameEditor({
      id: null,
      name: '',
      palette: { ...base },
      texture_url: null,
      frame_image_url: null,
      layout: {
        art: { ...DEFAULT_LAYOUT.art },
        text: { ...DEFAULT_LAYOUT.text },
      },
    });
  };

  const openEditFrameEditor = (frame) => {
    setFrameEditor({
      id: frame.id,
      name: frame.name,
      palette: { ...frame.palette },
      texture_url: frame.texture_url || null,
      frame_image_url: frame.frame_image_url || null,
      layout: frame.layout
        ? { art: { ...frame.layout.art }, text: { ...frame.layout.text } }
        : {
            art: { ...DEFAULT_LAYOUT.art },
            text: { ...DEFAULT_LAYOUT.text },
          },
    });
  };

  const handleSaveFrame = async () => {
    if (!frameEditor) return;
    const name = frameEditor.name.trim();
    if (!name) {
      setMessage({ kind: 'error', text: 'Give the frame a name first.' });
      return;
    }
    setSavingFrame(true);
    try {
      const isNew = !frameEditor.id;
      const response = await fetch(
        isNew ? '/api/custom-frames' : `/api/custom-frames/${frameEditor.id}`,
        {
          method: isNew ? 'POST' : 'PUT',
          headers: { 'Content-Type': 'application/json', ...authHeaders() },
          body: JSON.stringify({
            name,
            palette: frameEditor.palette,
            layout: frameEditor.layout,
          }),
        }
      );
      const data = await response.json();
      if (response.ok) {
        setFrames((prev) =>
          isNew
            ? [...prev, data.frame].sort((a, b) => a.name.localeCompare(b.name))
            : prev.map((f) => (f.id === data.frame.id ? data.frame : f))
        );
        setDesign((prev) => ({ ...prev, custom_frame_id: data.frame.id }));
        setFrameEditor(null);
        setMessage({ kind: 'success', text: `Frame "${data.frame.name}" saved.` });
      } else {
        setMessage({ kind: 'error', text: data.error || 'Could not save frame.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Could not save frame.' });
    } finally {
      setSavingFrame(false);
    }
  };

  const handleDeleteFrame = async (frameId) => {
    if (!window.confirm('Delete this frame? Cards using it fall back to their starter frame.')) return;
    try {
      const response = await fetch(`/api/custom-frames/${frameId}`, {
        method: 'DELETE',
        headers: authHeaders(),
      });
      if (response.ok) {
        setFrames((prev) => prev.filter((f) => f.id !== frameId));
        setDesign((prev) =>
          prev.custom_frame_id === frameId ? { ...prev, custom_frame_id: null } : prev
        );
        if (frameEditor?.id === frameId) setFrameEditor(null);
      } else {
        setMessage({ kind: 'error', text: 'Could not delete frame.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Could not delete frame.' });
    }
  };

  const handleSymbolUpload = async (file) => {
    const code = symbolCode.trim();
    if (!file || !code) return;
    setUploadingSymbol(true);
    try {
      const body = new FormData();
      body.append('code', code);
      body.append('image', file);
      const response = await fetch('/api/custom-symbols', {
        method: 'POST',
        headers: authHeaders(),
        body,
      });
      const data = await response.json();
      if (response.ok) {
        setSymbols((prev) => {
          const next = prev.filter((s) => s.code !== data.symbol.code);
          return [...next, data.symbol].sort((a, b) => a.code.localeCompare(b.code));
        });
        setSymbolCode('');
        setMessage({ kind: 'success', text: `Symbol {${data.symbol.code}} saved.` });
      } else {
        setMessage({ kind: 'error', text: data.error || 'Symbol upload failed.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Symbol upload failed.' });
    } finally {
      setUploadingSymbol(false);
      if (symbolFileRef.current) symbolFileRef.current.value = '';
    }
  };

  const handleDeleteSymbol = async (symbolId) => {
    try {
      const response = await fetch(`/api/custom-symbols/${symbolId}`, {
        method: 'DELETE',
        headers: authHeaders(),
      });
      if (response.ok) {
        setSymbols((prev) => prev.filter((s) => s.id !== symbolId));
      } else {
        setMessage({ kind: 'error', text: 'Could not delete symbol.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Could not delete symbol.' });
    }
  };

  const handleUploadTexture = async (file) => {
    if (!file || !frameEditor?.id) return;
    setUploadingTexture(true);
    try {
      const body = new FormData();
      body.append('texture', file);
      const response = await fetch(`/api/custom-frames/${frameEditor.id}/texture`, {
        method: 'POST',
        headers: authHeaders(),
        body,
      });
      const data = await response.json();
      if (response.ok && data.texture_url) {
        setFrames((prev) =>
          prev.map((f) =>
            f.id === frameEditor.id ? { ...f, texture_url: data.texture_url } : f
          )
        );
        setFrameEditor((prev) => ({ ...prev, texture_url: data.texture_url }));
        setMessage({ kind: 'success', text: 'Texture uploaded.' });
      } else {
        setMessage({ kind: 'error', text: data.error || 'Texture upload failed.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Texture upload failed.' });
    } finally {
      setUploadingTexture(false);
      if (textureFileRef.current) textureFileRef.current.value = '';
    }
  };

  const handleRemoveTexture = async () => {
    if (!frameEditor?.id) return;
    try {
      const response = await fetch(`/api/custom-frames/${frameEditor.id}/texture`, {
        method: 'DELETE',
        headers: authHeaders(),
      });
      if (response.ok) {
        setFrames((prev) =>
          prev.map((f) =>
            f.id === frameEditor.id ? { ...f, texture_url: null } : f
          )
        );
        setFrameEditor((prev) => ({ ...prev, texture_url: null }));
      } else {
        setMessage({ kind: 'error', text: 'Could not remove texture.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Could not remove texture.' });
    }
  };

  const handleUploadFrameImage = async (file) => {
    if (!file || !frameEditor?.id) return;
    setUploadingFrameImage(true);
    try {
      const body = new FormData();
      body.append('image', file);
      const response = await fetch(`/api/custom-frames/${frameEditor.id}/frame-image`, {
        method: 'POST',
        headers: authHeaders(),
        body,
      });
      const data = await response.json();
      if (response.ok && data.frame_image_url) {
        setFrames((prev) =>
          prev.map((f) =>
            f.id === frameEditor.id
              ? { ...f, frame_image_url: data.frame_image_url }
              : f
          )
        );
        setFrameEditor((prev) => ({ ...prev, frame_image_url: data.frame_image_url }));
        setMessage({ kind: 'success', text: 'Frame image uploaded — drag the windows to match it.' });
      } else {
        setMessage({ kind: 'error', text: data.error || 'Frame image upload failed.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Frame image upload failed.' });
    } finally {
      setUploadingFrameImage(false);
      if (frameImageFileRef.current) frameImageFileRef.current.value = '';
    }
  };

  const handleRemoveFrameImage = async () => {
    if (!frameEditor?.id) return;
    try {
      const response = await fetch(`/api/custom-frames/${frameEditor.id}/frame-image`, {
        method: 'DELETE',
        headers: authHeaders(),
      });
      if (response.ok) {
        setFrames((prev) =>
          prev.map((f) =>
            f.id === frameEditor.id ? { ...f, frame_image_url: null } : f
          )
        );
        setFrameEditor((prev) => ({ ...prev, frame_image_url: null }));
      } else {
        setMessage({ kind: 'error', text: 'Could not remove frame image.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Could not remove frame image.' });
    }
  };

  const symbolsMap = Object.fromEntries(symbols.map((s) => [s.code, s.image_url]));

  // Edit mode when ?id= is present
  useEffect(() => {
    if (!user || !router.query.id) return;

    const loadDesign = async () => {
      try {
        const token = localStorage.getItem('auth_token');
        const response = await fetch(`/api/custom-cards/${router.query.id}`, {
          headers: token ? { Authorization: `Bearer ${token}` } : {},
        });
        if (response.ok) {
          const data = await response.json();
          setDesign({ ...BLANK_DESIGN, ...data.design });
        } else {
          setMessage({ kind: 'error', text: 'Design not found.' });
        }
      } catch {
        setMessage({ kind: 'error', text: 'Failed to load design.' });
      }
    };

    loadDesign();
  }, [user, router.query.id]);

  // Preselect a custom game when ?game= is present
  useEffect(() => {
    if (!user || !router.query.game) return;
    const gameId = parseInt(router.query.game, 10);
    if (!Number.isInteger(gameId)) return;
    // eslint-disable-next-line react-hooks/set-state-in-effect -- URL param → form state sync
    setDesign((prev) =>
      prev.custom_game_id === gameId && prev.game_target === 'custom'
        ? prev
        : { ...prev, game_target: 'custom', custom_game_id: gameId }
    );
  }, [user, router.query.game]);

  const setField = useCallback((field, value) => {
    setDesign((prev) => ({ ...prev, [field]: value }));
  }, []);

  const handleUpload = async (file) => {
    if (!file) return;
    setUploading(true);
    setMessage(null);
    try {
      const body = new FormData();
      body.append('artwork', file);

      const token = localStorage.getItem('auth_token');
      const response = await fetch('/api/custom-cards/upload-artwork', {
        method: 'POST',
        headers: token ? { Authorization: `Bearer ${token}` } : undefined,
        body,
      });

      const data = await response.json();
      if (response.ok && data.artwork_url) {
        setField('artwork_url', data.artwork_url);
      } else {
        setMessage({ kind: 'error', text: data.error || 'Upload failed.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Upload failed. Please try again.' });
    } finally {
      setUploading(false);
    }
  };

  const handleSave = async () => {
    if (!design.name.trim()) {
      setMessage({ kind: 'error', text: 'Give your card a title first.' });
      return;
    }
    setSaving(true);
    setMessage(null);
    try {
      const token = localStorage.getItem('auth_token');
      const isNew = !design.id;
      const response = await fetch(
        isNew ? '/api/custom-cards' : `/api/custom-cards/${design.id}`,
        {
          method: isNew ? 'POST' : 'PUT',
          headers: {
            'Content-Type': 'application/json',
            ...(token ? { Authorization: `Bearer ${token}` } : {}),
          },
          body: JSON.stringify(design),
        }
      );
      const data = await response.json();
      if (response.ok) {
        setDesign({ ...BLANK_DESIGN, ...data.design });
        setMessage({
          kind: 'success',
          text: isNew ? 'Card saved to your designs!' : 'Changes saved.',
        });
      } else {
        setMessage({ kind: 'error', text: data.error || 'Save failed.' });
      }
    } catch {
      setMessage({ kind: 'error', text: 'Save failed. Please try again.' });
    } finally {
      setSaving(false);
    }
  };

  const handleExportPng = async () => {
    if (!cardRef.current) return;
    setExporting(true);
    try {
      const { toPng } = await import('html-to-image');
      const dataUrl = await toPng(cardRef.current, {
        width: 420,
        height: 588,
        pixelRatio: 2,
        cacheBust: true,
      });
      const link = document.createElement('a');
      link.download = `${(design.name || 'card').replace(/[^a-z0-9-_ ]/gi, '').trim() || 'card'}.png`;
      link.href = dataUrl;
      link.click();
    } catch {
      setMessage({ kind: 'error', text: 'Export failed. Please try again.' });
    } finally {
      setExporting(false);
    }
  };

  const handleNew = () => {
    setDesign(BLANK_DESIGN);
    setMessage(null);
    router.replace('/designer', undefined, { shallow: true });
  };

  if (authLoading) {
    return (
      <Layout user={user}>
        <div className="flex items-center justify-center min-h-screen">
          <div className="animate-spin rounded-full h-32 w-32 border-b-2" style={{ borderColor: 'var(--accent-ember)' }} />
        </div>
      </Layout>
    );
  }

  return (
    <Layout user={user}>
      <div className="p-4 sm:p-6 max-w-[1500px] mx-auto space-y-6">
        {/* Header */}
        <div className="pt-2 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
          <div>
            <h1 className="text-2xl sm:text-3xl font-bold mb-1" style={{ color: 'var(--text-primary)' }}>
              Card Designer
            </h1>
            <p className="text-base" style={{ color: 'var(--text-secondary)' }}>
              Fill in the details and watch your card come to life.
            </p>
          </div>
          <div className="flex gap-2">
            <Button variant="secondary" onClick={handleNew}>New</Button>
            <Button variant="secondary" onClick={handleExportPng} disabled={exporting}>
              {exporting ? 'Exporting…' : 'Download PNG'}
            </Button>
            <Button variant="primary" onClick={handleSave} disabled={saving}>
              {saving ? 'Saving…' : design.id ? 'Save Changes' : 'Save Card'}
            </Button>
          </div>
        </div>

        {message && (
          <div
            className="glass-panel rounded-xl px-4 py-3 text-sm"
            style={{ color: message.kind === 'error' ? '#f87171' : '#4ade80' }}
            role="status"
          >
            {message.text}
          </div>
        )}

        <div className="grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_460px] gap-6">
          {/* ── Form column ─────────────────────────────── */}
          <div className="space-y-5 min-w-0">
            {/* Game targeting */}
            <section className="glass-panel rounded-2xl p-5 space-y-3">
              <h2 className="text-sm font-semibold uppercase tracking-wide" style={{ color: 'var(--text-secondary)' }}>
                Game System
              </h2>
              <div className="flex flex-wrap rounded-xl overflow-hidden border" style={{ borderColor: 'var(--border)' }}>
                {[
                  { id: 'custom', label: 'Just my designs' },
                  { id: 'existing', label: 'Existing system' },
                  { id: 'custom-game', label: 'My custom game' },
                ].map((mode) => {
                  const active =
                    mode.id === 'custom'
                      ? design.game_target === 'custom' && !design.custom_game_id
                      : mode.id === 'existing'
                        ? design.game_target !== 'custom'
                        : Boolean(design.custom_game_id);
                  return (
                    <button
                      key={mode.id}
                      type="button"
                      onClick={() =>
                        setDesign((prev) => ({
                          ...prev,
                          game_target: mode.id === 'existing' ? 'MTG' : 'custom',
                          custom_game_id:
                            mode.id === 'custom-game' ? games[0]?.id || null : null,
                        }))
                      }
                      className="px-4 py-2 text-xs font-semibold transition-all duration-200"
                      style={{
                        backgroundColor: active ? 'var(--accent-ember)' : 'var(--bg-tertiary)',
                        color: active ? 'white' : 'var(--text-secondary)',
                      }}
                      aria-pressed={active}
                    >
                      {mode.label}
                    </button>
                  );
                })}
              </div>

              {design.game_target !== 'custom' && (
                <select
                  className="input-field w-full"
                  value={design.game_target}
                  onChange={(e) =>
                    setDesign((prev) => ({
                      ...prev,
                      game_target: e.target.value,
                      custom_game_id: null,
                    }))
                  }
                >
                  {EXISTING_GAMES.map((game) => (
                    <option key={game.value} value={game.value}>
                      {game.label}
                    </option>
                  ))}
                </select>
              )}

              {design.game_target === 'custom' && (
                <div className="space-y-2">
                  {games.length > 0 && (
                    <select
                      className="input-field w-full"
                      value={design.custom_game_id || ''}
                      onChange={(e) =>
                        setDesign((prev) => ({
                          ...prev,
                          custom_game_id: e.target.value ? parseInt(e.target.value, 10) : null,
                        }))
                      }
                    >
                      <option value="">— None (standalone) —</option>
                      {games.map((game) => (
                        <option key={game.id} value={game.id}>
                          {game.name} ({game.card_count})
                        </option>
                      ))}
                    </select>
                  )}
                  <div className="flex gap-2">
                    <input
                      className="input-field flex-1"
                      value={newGameName}
                      onChange={(e) => setNewGameName(e.target.value)}
                      onKeyDown={(e) => e.key === 'Enter' && handleCreateGame()}
                      placeholder="New game name…"
                      maxLength={100}
                    />
                    <Button
                      variant="secondary"
                      onClick={handleCreateGame}
                      disabled={creatingGame || !newGameName.trim()}
                    >
                      {creatingGame ? 'Creating…' : 'Create'}
                    </Button>
                  </div>
                  <p className="text-xs" style={{ color: 'var(--text-secondary)' }}>
                    Custom games group your designs — manage them in{' '}
                    <Link href="/games" style={{ color: 'var(--accent-ember)' }}>My Games</Link>.
                  </p>
                </div>
              )}
            </section>

            {/* Frame picker */}
            <section className="glass-panel rounded-2xl p-5">
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-sm font-semibold uppercase tracking-wide" style={{ color: 'var(--text-secondary)' }}>
                  Frame
                </h2>
                <Button variant="secondary" size="sm" onClick={openNewFrameEditor}>
                  + New Frame
                </Button>
              </div>
              <div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
                {FRAMES.map((frame) => {
                  const active = !design.custom_frame_id && design.frame_id === frame.id;
                  return (
                    <button
                      key={frame.id}
                      type="button"
                      onClick={() =>
                        setDesign((prev) => ({
                          ...prev,
                          frame_id: frame.id,
                          custom_frame_id: null,
                        }))
                      }
                      className={`rounded-xl p-3 text-left transition-all duration-200 border ${
                        active ? 'shadow-lg scale-[1.02]' : 'opacity-80 hover:opacity-100'
                      }`}
                      style={{
                        backgroundColor: frame.palette.outer,
                        borderColor: active ? frame.palette.border : 'transparent',
                        borderWidth: 2,
                      }}
                      aria-pressed={active}
                    >
                      <div
                        className="w-full h-8 rounded mb-2"
                        style={{
                          background: `linear-gradient(135deg, ${frame.palette.titleBar}, ${frame.palette.textBox})`,
                          border: `1px solid ${frame.palette.border}`,
                        }}
                      />
                      <span className="text-xs font-semibold block" style={{ color: frame.palette.titleText }}>
                        {frame.name}
                      </span>
                    </button>
                  );
                })}
                {frames.map((frame) => {
                  const p = frame.palette;
                  const active = design.custom_frame_id === frame.id;
                  return (
                    <div key={frame.id} className="relative">
                      <button
                        type="button"
                        onClick={() => setDesign((prev) => ({ ...prev, custom_frame_id: frame.id }))}
                        onDoubleClick={() => openEditFrameEditor(frame)}
                        className={`w-full rounded-xl p-3 text-left transition-all duration-200 border ${
                          active ? 'shadow-lg scale-[1.02]' : 'opacity-80 hover:opacity-100'
                        }`}
                        style={{
                          backgroundColor: p.outer,
                          borderColor: active ? p.border : 'transparent',
                          borderWidth: 2,
                        }}
                        aria-pressed={active}
                        title={`${frame.name} — double-click to edit`}
                      >
                        <div
                          className="w-full h-8 rounded mb-2"
                          style={{
                            background: `linear-gradient(135deg, ${p.titleBar}, ${p.textBox})`,
                            border: `1px solid ${p.border}`,
                          }}
                        />
                        <span className="text-xs font-semibold block truncate" style={{ color: p.titleText }}>
                          {frame.name}
                        </span>
                      </button>
                      <button
                        type="button"
                        onClick={() => openEditFrameEditor(frame)}
                        className="absolute top-1 right-1 text-[10px] px-1.5 py-0.5 rounded"
                        style={{ backgroundColor: 'rgba(0,0,0,0.55)', color: p.titleText }}
                        aria-label={`Edit ${frame.name}`}
                      >
                        Edit
                      </button>
                    </div>
                  );
                })}
              </div>

              {/* Frame editor */}
              {frameEditor && (
                <div className="mt-4 rounded-xl p-4 border" style={{ borderColor: 'var(--border)' }}>
                  <div className="flex flex-col lg:flex-row gap-4">
                    <div className="flex-1 space-y-3">
                      <div className="flex gap-2">
                        <input
                          className="input-field flex-1"
                          value={frameEditor.name}
                          onChange={(e) =>
                            setFrameEditor((prev) => ({ ...prev, name: e.target.value }))
                          }
                          placeholder="Frame name…"
                          maxLength={100}
                        />
                        <Button variant="primary" onClick={handleSaveFrame} disabled={savingFrame}>
                          {savingFrame ? 'Saving…' : frameEditor.id ? 'Update' : 'Save'}
                        </Button>
                        <Button variant="secondary" onClick={() => setFrameEditor(null)}>
                          Cancel
                        </Button>
                      </div>
                      <div className="grid grid-cols-2 sm:grid-cols-3 gap-2">
                        {PALETTE_SLOTS.map(({ key, label }) => (
                          <label key={key} className="flex items-center gap-2 text-xs" style={{ color: 'var(--text-secondary)' }}>
                            <input
                              type="color"
                              value={frameEditor.palette[key]}
                              onChange={(e) =>
                                setFrameEditor((prev) => ({
                                  ...prev,
                                  palette: { ...prev.palette, [key]: e.target.value },
                                }))
                              }
                              className="w-7 h-7 rounded cursor-pointer bg-transparent"
                              aria-label={label}
                            />
                            {label}
                          </label>
                        ))}
                      </div>
{frameEditor.id && (
                <div className="flex flex-wrap items-center gap-2">
                  <input
                    ref={textureFileRef}
                    type="file"
                    accept="image/jpeg,image/png,image/webp"
                    className="hidden"
                    onChange={(e) => handleUploadTexture(e.target.files?.[0])}
                  />
                  <Button
                    variant="secondary"
                    size="sm"
                    onClick={() => textureFileRef.current?.click()}
                    disabled={uploadingTexture}
                  >
                    {uploadingTexture
                      ? 'Uploading…'
                      : frameEditor.texture_url
                        ? 'Replace Texture'
                        : 'Upload Texture'}
                  </Button>
                  {frameEditor.texture_url && (
                    <Button variant="secondary" size="sm" onClick={handleRemoveTexture}>
                      Remove Texture
                    </Button>
                  )}
                  <input
                    ref={frameImageFileRef}
                    type="file"
                    accept="image/png,image/webp"
                    className="hidden"
                    onChange={(e) => handleUploadFrameImage(e.target.files?.[0])}
                  />
                  <Button
                    variant="secondary"
                    size="sm"
                    onClick={() => frameImageFileRef.current?.click()}
                    disabled={uploadingFrameImage}
                  >
                    {uploadingFrameImage
                      ? 'Uploading…'
                      : frameEditor.frame_image_url
                        ? 'Replace Frame Image'
                        : 'Upload Frame Image'}
                  </Button>
                  {frameEditor.frame_image_url && (
                    <Button variant="secondary" size="sm" onClick={handleRemoveFrameImage}>
                      Remove Frame Image
                    </Button>
                  )}
                  <Button variant="secondary" size="sm" onClick={() => handleDeleteFrame(frameEditor.id)}>
                    Delete Frame
                  </Button>
                  <span className="text-xs" style={{ color: 'var(--text-secondary)' }}>
                    {frameEditor.frame_image_url
                      ? 'Drag the ARTWORK/TEXT windows to fit your image.'
                      : 'Textures show behind the frame panels. Save first to upload a full frame PNG with transparent windows.'}
                  </span>
                </div>
              )}
              {!frameEditor.id && (
                <p className="text-xs" style={{ color: 'var(--text-secondary)' }}>
                  Save the frame first to add a background texture or full frame image.
                </p>
              )}
              {frameEditor.frame_image_url && (
                <div className="mt-4 rounded-xl p-4 border" style={{ borderColor: 'var(--border)' }}>
                  <p className="text-sm font-semibold mb-2" style={{ color: 'var(--text-primary)' }}>
                    Window Editor
                  </p>
                  <ZoneEditor
                    frameImageUrl={frameEditor.frame_image_url}
                    layout={frameEditor.layout}
                    onChange={(next) =>
                      setFrameEditor((prev) => ({ ...prev, layout: next }))
                    }
                  />
                </div>
              )}
                    </div>
                    <div className="w-full max-w-[240px] shrink-0">
                      <p className="text-xs mb-2 text-center" style={{ color: 'var(--text-secondary)' }}>
                        Live frame preview
                      </p>
                      <CardFrame
                        design={{
                          ...design,
                          custom_frame: {
                            palette: frameEditor.palette,
                            texture_url: frameEditor.texture_url,
                            frame_image_url: frameEditor.frame_image_url,
                            layout: frameEditor.layout,
                          },
                        }}
                        symbols={symbolsMap}
                      />
                    </div>
                  </div>
                </div>
              )}
            </section>

            {/* Cost symbols */}
            <section className="glass-panel rounded-2xl p-5">
              <h2 className="text-sm font-semibold uppercase tracking-wide mb-1" style={{ color: 'var(--text-secondary)' }}>
                Cost Symbols
              </h2>
              <p className="text-xs mb-3" style={{ color: 'var(--text-secondary)' }}>
                Upload small icons and use them in the Cost field as <code>{'{CODE}'}</code> or plain letters — e.g.{' '}
                <code>{'2{F}{F}'}</code>.
              </p>

              {symbols.length > 0 && (
                <div className="flex flex-wrap gap-2 mb-3">
                  {symbols.map((symbol) => (
                    <span
                      key={symbol.id}
                      className="inline-flex items-center gap-2 rounded-full pl-1 pr-2 py-1 border text-xs font-semibold"
                      style={{ borderColor: 'var(--border)', color: 'var(--text-primary)' }}
                    >
                      {/* eslint-disable-next-line @next/next/no-img-element -- CDN icon */}
                      <img
                        src={symbol.image_url}
                        alt={symbol.code}
                        className="w-6 h-6 rounded-full object-cover"
                      />
                      {symbol.code}
                      <button
                        type="button"
                        onClick={() => handleDeleteSymbol(symbol.id)}
                        className="ml-1 opacity-60 hover:opacity-100"
                        aria-label={`Delete symbol ${symbol.code}`}
                      >
                        ×
                      </button>
                    </span>
                  ))}
                </div>
              )}

              <input
                ref={symbolFileRef}
                type="file"
                accept="image/png,image/webp,image/svg+xml"
                className="hidden"
                onChange={(e) => handleSymbolUpload(e.target.files?.[0])}
              />
              <div className="flex flex-wrap gap-2 items-center">
                <input
                  className="input-field w-28"
                  value={symbolCode}
                  onChange={(e) => setSymbolCode(e.target.value)}
                  placeholder="Code (F)"
                  maxLength={10}
                />
                <Button
                  variant="primary"
                  onClick={() => symbolFileRef.current?.click()}
                  disabled={uploadingSymbol || !symbolCode.trim()}
                >
                  {uploadingSymbol ? 'Uploading…' : 'Upload Icon'}
                </Button>
                <span className="text-xs" style={{ color: 'var(--text-secondary)' }}>
                  PNG, WebP, or SVG · up to 2MB · re-uploading a code replaces it
                </span>
              </div>
            </section>

            {/* Artwork */}
            <section className="glass-panel rounded-2xl p-5">
              <h2 className="text-sm font-semibold uppercase tracking-wide mb-3" style={{ color: 'var(--text-secondary)' }}>
                Artwork
              </h2>
              <input
                ref={fileInputRef}
                type="file"
                accept="image/jpeg,image/png,image/webp"
                className="hidden"
                onChange={(e) => handleUpload(e.target.files?.[0])}
              />
              <div className="flex flex-wrap items-center gap-3">
                <div className="flex rounded-xl overflow-hidden border" style={{ borderColor: 'var(--border)' }}>
                  {[
                    { id: 'framed', label: 'Framed' },
                    { id: 'fullart', label: 'Full Art' },
                  ].map((mode) => (
                    <button
                      key={mode.id}
                      type="button"
                      onClick={() => setField('art_mode', mode.id)}
                      className="px-4 py-2 text-xs font-semibold transition-all duration-200"
                      style={{
                        backgroundColor:
                          design.art_mode === mode.id ? 'var(--accent-ember)' : 'var(--bg-tertiary)',
                        color: design.art_mode === mode.id ? 'white' : 'var(--text-secondary)',
                      }}
                      aria-pressed={design.art_mode === mode.id}
                    >
                      {mode.label}
                    </button>
                  ))}
                </div>
                <Button variant="primary" onClick={() => fileInputRef.current?.click()} disabled={uploading}>
                  {uploading ? 'Uploading…' : design.artwork_url ? 'Replace Image' : 'Upload Image'}
                </Button>
                {design.artwork_url && (
                  <Button variant="secondary" onClick={() => setField('artwork_url', '')}>
                    Remove
                  </Button>
                )}
                <span className="text-xs" style={{ color: 'var(--text-secondary)' }}>
                  JPEG, PNG, or WebP · up to 5MB
                </span>
              </div>
            </section>

            {/* Details */}
            <section className="glass-panel rounded-2xl p-5 space-y-4">
              <h2 className="text-sm font-semibold uppercase tracking-wide" style={{ color: 'var(--text-secondary)' }}>
                Details
              </h2>

              <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                <Field label="Title" required>
                  <input
                    className="input-field w-full"
                    value={design.name}
                    onChange={(e) => setField('name', e.target.value)}
                    placeholder="Emberwing Phoenix"
                    maxLength={60}
                  />
                </Field>
                <Field label="Cost" hint='e.g. "2RR" or "{2}{R}{R}"'>
                  <input
                    className="input-field w-full"
                    value={design.mana_cost}
                    onChange={(e) => setField('mana_cost', e.target.value)}
                    placeholder="2RR"
                    maxLength={24}
                  />
                </Field>
              </div>

              <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                <Field label="Type">
                  <input
                    className="input-field w-full"
                    value={design.card_type}
                    onChange={(e) => setField('card_type', e.target.value)}
                    placeholder="Creature — Phoenix"
                    maxLength={80}
                  />
                </Field>
                <Field label="Rarity">
                  <div className="flex gap-2">
                    {RARITIES.map((rarity) => (
                      <button
                        key={rarity.id}
                        type="button"
                        onClick={() => setField('rarity', rarity.id)}
                        className={`flex-1 rounded-lg px-2 py-2 text-xs font-semibold transition-all duration-200 ${
                          design.rarity === rarity.id ? 'scale-105 shadow-md' : 'opacity-70 hover:opacity-100'
                        }`}
                        style={{
                          backgroundColor: 'var(--bg-tertiary)',
                          color: design.rarity === rarity.id ? rarity.color : 'var(--text-secondary)',
                          borderBottom: `3px solid ${rarity.color}`,
                        }}
                        aria-pressed={design.rarity === rarity.id}
                      >
                        {rarity.name}
                      </button>
                    ))}
                  </div>
                </Field>
              </div>

              <Field label="Description">
                <textarea
                  className="input-field w-full resize-y"
                  rows={3}
                  value={design.rules_text}
                  onChange={(e) => setField('rules_text', e.target.value)}
                  placeholder="What the card does, or what it describes…"
                  maxLength={500}
                />
              </Field>

              <Field label="Actions / Abilities">
                <textarea
                  className="input-field w-full resize-y"
                  rows={3}
                  value={design.actions}
                  onChange={(e) => setField('actions', e.target.value)}
                  placeholder={'Flying, haste\nWhen Emberwing enters the battlefield, it deals 2 damage to any target.'}
                  maxLength={800}
                />
              </Field>

              <Field label="Flavor Quote" hint="shown in italics with decorative dividers">
                <textarea
                  className="input-field w-full resize-y"
                  rows={2}
                  value={design.flavor_quote}
                  onChange={(e) => setField('flavor_quote', e.target.value)}
                  placeholder="From the ashes, memory takes wing."
                  maxLength={300}
                />
              </Field>

              <details className="text-sm" style={{ color: 'var(--text-secondary)' }}>
                <summary className="cursor-pointer select-none">Power / Toughness (optional)</summary>
                <div className="grid grid-cols-2 gap-4 mt-3">
                  <Field label="Power">
                    <input
                      className="input-field w-full"
                      value={design.power}
                      onChange={(e) => setField('power', e.target.value)}
                      placeholder="3"
                      maxLength={10}
                    />
                  </Field>
                  <Field label="Toughness">
                    <input
                      className="input-field w-full"
                      value={design.toughness}
                      onChange={(e) => setField('toughness', e.target.value)}
                      placeholder="4"
                      maxLength={10}
                    />
                  </Field>
                </div>
              </details>
            </section>
          </div>

          {/* ── Live preview column ─────────────────────── */}
          <div>
            <div className="sticky top-8 glass-panel rounded-2xl p-6">
              <h2 className="text-sm font-semibold uppercase tracking-wide mb-4" style={{ color: 'var(--text-secondary)' }}>
                Live Preview
              </h2>
              <CardPreview design={design} innerRef={cardRef} symbols={symbolsMap} />
              <p className="text-xs mt-4 text-center" style={{ color: 'var(--text-secondary)' }}>
                Saved designs appear in{' '}
                <Link href="/my-designs" style={{ color: 'var(--accent-ember)' }}>My Designs</Link>{' '}
                and your collection.
              </p>
            </div>
          </div>
        </div>
      </div>
    </Layout>
  );
}

function Field({ label, hint, required, children }) {
  return (
    <label className="block">
      <span className="text-xs font-semibold mb-1.5 block" style={{ color: 'var(--text-primary)' }}>
        {label}
        {required && <span style={{ color: 'var(--accent-ember)' }}> *</span>}
        {hint && (
          <span className="font-normal ml-2" style={{ color: 'var(--text-secondary)' }}>
            ({hint})
          </span>
        )}
      </span>
      {children}
    </label>
  );
}
