'use client';

import { useEffect, useMemo, useRef, useState } from 'react';
import { Download, Printer, Loader2, Upload, X } from 'lucide-react';
import { qrToDataUrl, qrToSvgString, downloadBlob, dataUrlToBlob, type QrStyle, type QrFrame } from '@client/utils/qr';

interface Props {
  url: string;
  style?: QrStyle;
  onChange?: (style: QrStyle) => void;
  filename?: string;
  caption?: string;
  compact?: boolean;
}

export default function QrDesigner({ url, style, onChange, filename = 'qr', caption, compact = false }: Props) {
  const merged: QrStyle = useMemo(() => ({
    fg: style?.fg ?? '#111827',
    bg: style?.bg ?? '#ffffff',
    margin: typeof style?.margin === 'number' ? style.margin : 2,
    ecc: (style?.ecc as 'L' | 'M' | 'Q' | 'H') ?? 'M',
    logo_data_url: style?.logo_data_url ?? null,
    frame: (style?.frame as QrFrame | null) ?? 'none',
  }), [style]);

  const [dataUrl, setDataUrl] = useState<string>('');
  const [busy, setBusy] = useState(false);
  const fileInputRef = useRef<HTMLInputElement | null>(null);
  const [logoError, setLogoError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    setBusy(true);
    qrToDataUrl(url, merged, 320)
      .then((d) => { if (!cancelled) setDataUrl(d); })
      .catch(() => { /* ignore */ })
      .finally(() => { if (!cancelled) setBusy(false); });
    return () => { cancelled = true; };
  }, [url, merged]);

  const update = (patch: Partial<QrStyle>) => onChange?.({ ...merged, ...patch });

  const downloadPng = () => {
    if (!dataUrl) return;
    downloadBlob(dataUrlToBlob(dataUrl), `${filename}.png`);
  };
  const downloadSvg = async () => {
    const svg = await qrToSvgString(url, merged, 320);
    downloadBlob(new Blob([svg], { type: 'image/svg+xml' }), `${filename}.svg`);
  };

  return (
    <div className={compact ? 'flex items-center gap-3' : 'grid grid-cols-1 md:grid-cols-2 gap-6'}>
      <div className={compact ? '' : 'flex flex-col items-center justify-center bg-slate-50 rounded-xl border border-slate-200 p-6'}>
        <div
          className="rounded-lg p-3"
          style={{ background: merged.bg }}
        >
          {busy && !dataUrl ? (
            <div className={compact ? 'w-16 h-16' : 'w-64 h-64'}><Loader2 className="animate-spin mx-auto mt-8 text-slate-400" /></div>
          ) : dataUrl ? (
            // eslint-disable-next-line @next/next/no-img-element
            <img src={dataUrl} alt="QR code" className={compact ? 'w-16 h-16' : 'w-64 h-64'} />
          ) : null}
        </div>
        {caption && <p className="text-xs text-slate-500 mt-2 text-center font-medium">{caption}</p>}
      </div>

      {!compact && (
        <div className="space-y-3">
          {onChange && (
            <>
              <div>
                <label className="text-xs font-semibold text-slate-700">Foreground</label>
                <div className="flex items-center gap-2 mt-1">
                  <input type="color" value={merged.fg} onChange={(e) => update({ fg: e.target.value })} className="w-12 h-8 rounded border border-slate-200" />
                  <input type="text" value={merged.fg} onChange={(e) => update({ fg: e.target.value })} className="flex-1 rounded-lg border border-slate-200 px-3 py-1.5 text-sm" />
                </div>
              </div>
              <div>
                <label className="text-xs font-semibold text-slate-700">Background</label>
                <div className="flex items-center gap-2 mt-1">
                  <input type="color" value={merged.bg} onChange={(e) => update({ bg: e.target.value })} className="w-12 h-8 rounded border border-slate-200" />
                  <input type="text" value={merged.bg} onChange={(e) => update({ bg: e.target.value })} className="flex-1 rounded-lg border border-slate-200 px-3 py-1.5 text-sm" />
                </div>
              </div>
              <div className="grid grid-cols-2 gap-3">
                <div>
                  <label className="text-xs font-semibold text-slate-700">Margin</label>
                  <input type="number" min={0} max={8} value={merged.margin} onChange={(e) => update({ margin: Math.max(0, Math.min(8, Number(e.target.value) || 0)) })} className="mt-1 w-full rounded-lg border border-slate-200 px-3 py-1.5 text-sm" />
                </div>
                <div>
                  <label className="text-xs font-semibold text-slate-700">Error correction</label>
                  <select value={merged.ecc} onChange={(e) => update({ ecc: e.target.value as 'L' | 'M' | 'Q' | 'H' })} className="mt-1 w-full rounded-lg border border-slate-200 px-3 py-1.5 text-sm bg-white">
                    <option value="L">Low</option>
                    <option value="M">Medium</option>
                    <option value="Q">Quartile</option>
                    <option value="H">High</option>
                  </select>
                </div>
              </div>
              <div>
                <label className="text-xs font-semibold text-slate-700">Print frame</label>
                <select
                  value={merged.frame ?? 'none'}
                  onChange={(e) => update({ frame: e.target.value as QrFrame })}
                  className="mt-1 w-full rounded-lg border border-slate-200 px-3 py-1.5 text-sm bg-white"
                >
                  <option value="none">No border</option>
                  <option value="scan-me">Rounded &ldquo;Scan to order&rdquo; frame</option>
                </select>
              </div>
              <div>
                <label className="text-xs font-semibold text-slate-700">Center logo (optional)</label>
                <input
                  ref={fileInputRef}
                  type="file"
                  accept="image/png,image/jpeg,image/svg+xml"
                  className="hidden"
                  onChange={(e) => {
                    const f = e.target.files?.[0];
                    if (!f) return;
                    if (f.size > 200 * 1024) {
                      setLogoError('Logo must be under 200 KB');
                      if (fileInputRef.current) fileInputRef.current.value = '';
                      return;
                    }
                    setLogoError(null);
                    const reader = new FileReader();
                    reader.onload = () => {
                      const result = reader.result;
                      if (typeof result === 'string') update({ logo_data_url: result });
                    };
                    reader.readAsDataURL(f);
                    if (fileInputRef.current) fileInputRef.current.value = '';
                  }}
                />
                <div className="mt-1 flex items-center gap-2">
                  <button
                    type="button"
                    onClick={() => fileInputRef.current?.click()}
                    className="flex items-center gap-1.5 bg-white border border-slate-200 hover:bg-slate-50 text-slate-700 text-xs font-semibold px-3 py-1.5 rounded-lg"
                  >
                    <Upload size={14} /> {merged.logo_data_url ? 'Replace logo' : 'Upload logo'}
                  </button>
                  {merged.logo_data_url && (
                    <button
                      type="button"
                      onClick={() => update({ logo_data_url: null })}
                      className="flex items-center gap-1 text-xs font-semibold text-rose-600 hover:text-rose-700"
                    >
                      <X size={14} /> Remove
                    </button>
                  )}
                </div>
                {logoError && <p className="text-[11px] text-rose-600 mt-1">{logoError}</p>}
                <p className="text-[11px] text-slate-400 mt-1">PNG / JPG / SVG up to 200 KB. Error-correction is auto-set to High when a logo is used.</p>
              </div>
            </>
          )}
          <div className="flex gap-2 pt-2">
            <button onClick={downloadPng} disabled={!dataUrl} className="flex items-center gap-1.5 bg-slate-900 hover:bg-slate-800 text-white text-xs font-semibold px-3 py-2 rounded-lg disabled:opacity-50">
              <Download size={14} /> PNG
            </button>
            <button onClick={downloadSvg} className="flex items-center gap-1.5 bg-white border border-slate-200 hover:bg-slate-50 text-slate-700 text-xs font-semibold px-3 py-2 rounded-lg">
              <Download size={14} /> SVG
            </button>
            <a href={url} target="_blank" rel="noopener noreferrer" className="flex items-center gap-1.5 bg-white border border-slate-200 hover:bg-slate-50 text-slate-700 text-xs font-semibold px-3 py-2 rounded-lg ml-auto">
              <Printer size={14} /> Open
            </a>
          </div>
          <p className="text-[11px] text-slate-400 break-all">{url}</p>
        </div>
      )}
    </div>
  );
}
