// CSS Loader Generator — pick from 12 animated loader presets, customize color & size,
// copy the HTML + CSS.

window.TOOL_HANDLERS['css-loader'] = function CssLoaderTool() {
  const LOADERS = [
    { id: 'spinner',      name: 'Spinner' },
    { id: 'dots',         name: 'Dots' },
    { id: 'ring',         name: 'Ring' },
    { id: 'pulse',        name: 'Pulse' },
    { id: 'bars',         name: 'Bars' },
    { id: 'dual-ring',    name: 'Dual Ring' },
    { id: 'ripple',       name: 'Ripple' },
    { id: 'ellipsis',     name: 'Ellipsis' },
    { id: 'grid',         name: 'Grid' },
    { id: 'roller',       name: 'Roller' },
    { id: 'hourglass',    name: 'Hourglass' },
    { id: 'square-spin',  name: 'Square Spin' },
  ];

  const [selected, setSelected] = React.useState('spinner');
  const [color, setColor] = React.useState('#3b82f6');
  const [size, setSize] = React.useState(48);
  const [copied, setCopied] = React.useState(false);

  // Inject the keyframe styles once
  React.useEffect(() => {
    if (document.getElementById('mm-loader-keyframes')) return;
    const style = document.createElement('style');
    style.id = 'mm-loader-keyframes';
    style.textContent = `
      @keyframes mm-loader-spin { to { transform: rotate(360deg); } }
      @keyframes mm-loader-bounce {
        0%, 80%, 100% { transform: scale(0); }
        40% { transform: scale(1); }
      }
      @keyframes mm-loader-pulse {
        0% { transform: scale(0.8); opacity: 1; }
        50% { transform: scale(1.2); opacity: 0.5; }
        100% { transform: scale(0.8); opacity: 1; }
      }
      @keyframes mm-loader-bars {
        0%, 40%, 100% { transform: scaleY(0.4); }
        20% { transform: scaleY(1); }
      }
      @keyframes mm-loader-ripple {
        0% { width: 0; height: 0; opacity: 1; }
        100% { width: 100%; height: 100%; opacity: 0; }
      }
      @keyframes mm-loader-ellipsis1 {
        0% { transform: scale(0); } 100% { transform: scale(1); }
      }
      @keyframes mm-loader-ellipsis2 {
        0% { transform: translateX(0); } 100% { transform: translateX(calc(var(--mm-sz) * 0.55)); }
      }
      @keyframes mm-loader-ellipsis3 {
        0% { transform: scale(1); } 100% { transform: scale(0); }
      }
      @keyframes mm-loader-grid {
        0%, 100% { opacity: 1; } 50% { opacity: 0.3; }
      }
      @keyframes mm-loader-roller {
        0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); }
      }
      @keyframes mm-loader-hourglass {
        0% { transform: rotate(0); }
        100% { transform: rotate(720deg); }
      }
      @keyframes mm-loader-square {
        0% { transform: perspective(120px) rotateX(0) rotateY(0); }
        25% { transform: perspective(120px) rotateX(-180deg) rotateY(0); }
        50% { transform: perspective(120px) rotateX(-180deg) rotateY(-180deg); }
        75% { transform: perspective(120px) rotateX(0) rotateY(-180deg); }
        100% { transform: perspective(120px) rotateX(0) rotateY(0); }
      }
    `;
    document.head.appendChild(style);
  }, []);

  // Generate inline HTML for each loader type at a given size/color
  const getLoaderStyle = (id, sz, clr) => {
    const u = sz / 48; // scale unit relative to 48px base
    const styles = {
      'spinner': {
        width: sz, height: sz, border: `${3 * u}px solid color-mix(in srgb, ${clr} 25%, transparent)`,
        borderTop: `${3 * u}px solid ${clr}`, borderRadius: '50%',
        animation: 'mm-loader-spin 0.8s linear infinite', boxSizing: 'border-box',
      },
      'dots': {
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: sz * 0.12,
        width: sz, height: sz,
      },
      'ring': {
        width: sz, height: sz, border: `${3 * u}px solid transparent`,
        borderTop: `${3 * u}px solid ${clr}`, borderBottom: `${3 * u}px solid ${clr}`,
        borderRadius: '50%', animation: 'mm-loader-spin 1s linear infinite', boxSizing: 'border-box',
      },
      'pulse': {
        width: sz * 0.6, height: sz * 0.6, backgroundColor: clr, borderRadius: '50%',
        animation: 'mm-loader-pulse 1.2s ease-in-out infinite',
      },
      'bars': {
        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: sz * 0.06,
        width: sz, height: sz,
      },
      'dual-ring': {
        width: sz, height: sz, position: 'relative',
      },
      'ripple': {
        width: sz, height: sz, position: 'relative',
      },
      'ellipsis': {
        width: sz, height: sz * 0.3, position: 'relative', display: 'flex',
        alignItems: 'center',
      },
      'grid': {
        display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: sz * 0.06,
        width: sz, height: sz,
      },
      'roller': {
        width: sz, height: sz, position: 'relative',
      },
      'hourglass': {
        width: sz * 0.5, height: sz * 0.5, border: `${4 * u}px solid ${clr}`,
        borderColor: `${clr} transparent`, borderRadius: '50%',
        animation: 'mm-loader-hourglass 1.2s linear infinite', boxSizing: 'border-box',
      },
      'square-spin': {
        width: sz * 0.5, height: sz * 0.5, backgroundColor: clr,
        animation: 'mm-loader-square 1.8s infinite ease-in-out',
      },
    };
    return styles[id] || {};
  };

  const renderLoader = (id, sz, clr) => {
    const s = getLoaderStyle(id, sz, clr);
    const u = sz / 48;
    const dotSz = sz * 0.18;

    switch (id) {
      case 'dots':
        return (
          <div style={s}>
            {[0, 1, 2].map((i) => (
              <div key={i} style={{
                width: dotSz, height: dotSz, borderRadius: '50%', backgroundColor: clr,
                animation: `mm-loader-bounce 1.2s ${i * 0.16}s ease-in-out infinite`,
              }} />
            ))}
          </div>
        );
      case 'bars':
        return (
          <div style={s}>
            {[0, 1, 2].map((i) => (
              <div key={i} style={{
                width: sz * 0.12, height: sz * 0.6, backgroundColor: clr, borderRadius: 2 * u,
                animation: `mm-loader-bars 1s ${i * 0.15}s ease-in-out infinite`,
                transformOrigin: 'center',
              }} />
            ))}
          </div>
        );
      case 'dual-ring':
        return (
          <div style={s}>
            <div style={{
              position: 'absolute', inset: 0, border: `${3 * u}px solid transparent`,
              borderTop: `${3 * u}px solid ${clr}`, borderRadius: '50%',
              animation: 'mm-loader-spin 0.9s linear infinite', boxSizing: 'border-box',
            }} />
            <div style={{
              position: 'absolute', inset: sz * 0.18, border: `${2.5 * u}px solid transparent`,
              borderBottom: `${2.5 * u}px solid ${clr}`, borderRadius: '50%',
              animation: 'mm-loader-spin 0.9s linear infinite reverse', boxSizing: 'border-box',
            }} />
          </div>
        );
      case 'ripple':
        return (
          <div style={s}>
            {[0, 1].map((i) => (
              <div key={i} style={{
                position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
                border: `${3 * u}px solid ${clr}`, borderRadius: '50%', opacity: 0.6,
                animation: `mm-loader-ripple 1.4s ${i * 0.5}s ease-out infinite`,
              }} />
            ))}
          </div>
        );
      case 'ellipsis': {
        const d = sz * 0.2;
        return (
          <div style={{ ...s, '--mm-sz': sz + 'px' }}>
            {[0, 1, 2, 3].map((i) => (
              <div key={i} style={{
                position: 'absolute', width: d, height: d, borderRadius: '50%', backgroundColor: clr,
                left: sz * 0.08 + (i === 3 ? sz * 0.55 : i === 0 ? 0 : i * sz * 0.27),
                animation: i === 0
                  ? `mm-loader-ellipsis1 0.6s infinite`
                  : i === 3
                    ? `mm-loader-ellipsis3 0.6s infinite`
                    : `mm-loader-ellipsis2 0.6s infinite`,
                animationDelay: i === 1 ? '-0.3s' : '0s',
              }} />
            ))}
          </div>
        );
      }
      case 'grid':
        return (
          <div style={s}>
            {Array.from({ length: 9 }).map((_, i) => (
              <div key={i} style={{
                backgroundColor: clr, borderRadius: 2 * u,
                animation: `mm-loader-grid 1.2s ${(i % 3 + Math.floor(i / 3)) * 0.15}s ease-in-out infinite`,
              }} />
            ))}
          </div>
        );
      case 'roller':
        return (
          <div style={{ ...s, animation: 'mm-loader-roller 1.2s linear infinite' }}>
            {[0, 1, 2, 3, 4, 5].map((i) => {
              const angle = (i / 6) * Math.PI * 2;
              const r = sz * 0.35;
              const cx = sz / 2 + Math.cos(angle) * r - dotSz / 2;
              const cy = sz / 2 + Math.sin(angle) * r - dotSz / 2;
              return (
                <div key={i} style={{
                  position: 'absolute', width: dotSz * 0.7, height: dotSz * 0.7,
                  borderRadius: '50%', backgroundColor: clr,
                  left: cx, top: cy, opacity: 1 - i * 0.14,
                }} />
              );
            })}
          </div>
        );
      default:
        return <div style={s} />;
    }
  };

  // Generate copyable HTML + CSS
  const getCode = () => {
    const sz = size;
    const clr = color;
    const u = sz / 48;
    const codeMap = {
      'spinner': {
        html: `<div class="mm-loader-spinner"></div>`,
        css: `.mm-loader-spinner {
  width: ${sz}px; height: ${sz}px;
  border: ${(3 * u).toFixed(1)}px solid color-mix(in srgb, ${clr} 25%, transparent);
  border-top-color: ${clr};
  border-radius: 50%;
  animation: mm-loader-spin 0.8s linear infinite;
  box-sizing: border-box;
}
@keyframes mm-loader-spin { to { transform: rotate(360deg); } }`,
      },
      'dots': {
        html: `<div class="mm-loader-dots">
  <div></div><div></div><div></div>
</div>`,
        css: `.mm-loader-dots { display: flex; align-items: center; gap: ${(sz * 0.12).toFixed(0)}px; }
.mm-loader-dots div {
  width: ${(sz * 0.18).toFixed(0)}px; height: ${(sz * 0.18).toFixed(0)}px;
  border-radius: 50%; background: ${clr};
  animation: mm-loader-bounce 1.2s ease-in-out infinite;
}
.mm-loader-dots div:nth-child(2) { animation-delay: 0.16s; }
.mm-loader-dots div:nth-child(3) { animation-delay: 0.32s; }
@keyframes mm-loader-bounce {
  0%, 80%, 100% { transform: scale(0); }
  40% { transform: scale(1); }
}`,
      },
      'ring': {
        html: `<div class="mm-loader-ring"></div>`,
        css: `.mm-loader-ring {
  width: ${sz}px; height: ${sz}px;
  border: ${(3 * u).toFixed(1)}px solid transparent;
  border-top-color: ${clr}; border-bottom-color: ${clr};
  border-radius: 50%; box-sizing: border-box;
  animation: mm-loader-spin 1s linear infinite;
}
@keyframes mm-loader-spin { to { transform: rotate(360deg); } }`,
      },
      'pulse': {
        html: `<div class="mm-loader-pulse"></div>`,
        css: `.mm-loader-pulse {
  width: ${(sz * 0.6).toFixed(0)}px; height: ${(sz * 0.6).toFixed(0)}px;
  background: ${clr}; border-radius: 50%;
  animation: mm-loader-pulse 1.2s ease-in-out infinite;
}
@keyframes mm-loader-pulse {
  0% { transform: scale(0.8); opacity: 1; }
  50% { transform: scale(1.2); opacity: 0.5; }
  100% { transform: scale(0.8); opacity: 1; }
}`,
      },
      'bars': {
        html: `<div class="mm-loader-bars">
  <div></div><div></div><div></div>
</div>`,
        css: `.mm-loader-bars {
  display: flex; align-items: center; gap: ${(sz * 0.06).toFixed(0)}px;
  height: ${sz}px;
}
.mm-loader-bars div {
  width: ${(sz * 0.12).toFixed(0)}px; height: ${(sz * 0.6).toFixed(0)}px;
  background: ${clr}; border-radius: ${(2 * u).toFixed(0)}px;
  animation: mm-loader-bars 1s ease-in-out infinite;
}
.mm-loader-bars div:nth-child(2) { animation-delay: 0.15s; }
.mm-loader-bars div:nth-child(3) { animation-delay: 0.3s; }
@keyframes mm-loader-bars {
  0%, 40%, 100% { transform: scaleY(0.4); }
  20% { transform: scaleY(1); }
}`,
      },
      'dual-ring': {
        html: `<div class="mm-loader-dual-ring">
  <div></div><div></div>
</div>`,
        css: `.mm-loader-dual-ring {
  width: ${sz}px; height: ${sz}px; position: relative;
}
.mm-loader-dual-ring div {
  position: absolute; border-radius: 50%; box-sizing: border-box;
  animation: mm-loader-spin 0.9s linear infinite;
}
.mm-loader-dual-ring div:first-child {
  inset: 0; border: ${(3 * u).toFixed(1)}px solid transparent;
  border-top-color: ${clr};
}
.mm-loader-dual-ring div:last-child {
  inset: ${(sz * 0.18).toFixed(0)}px;
  border: ${(2.5 * u).toFixed(1)}px solid transparent;
  border-bottom-color: ${clr};
  animation-direction: reverse;
}
@keyframes mm-loader-spin { to { transform: rotate(360deg); } }`,
      },
      'ripple': {
        html: `<div class="mm-loader-ripple">
  <div></div><div></div>
</div>`,
        css: `.mm-loader-ripple {
  width: ${sz}px; height: ${sz}px; position: relative;
}
.mm-loader-ripple div {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  border: ${(3 * u).toFixed(1)}px solid ${clr};
  border-radius: 50%; opacity: 0.6;
  animation: mm-loader-ripple 1.4s ease-out infinite;
}
.mm-loader-ripple div:last-child { animation-delay: 0.5s; }
@keyframes mm-loader-ripple {
  0% { width: 0; height: 0; opacity: 1; }
  100% { width: 100%; height: 100%; opacity: 0; }
}`,
      },
      'ellipsis': {
        html: `<div class="mm-loader-ellipsis">
  <div></div><div></div><div></div><div></div>
</div>`,
        css: `.mm-loader-ellipsis {
  width: ${sz}px; height: ${(sz * 0.3).toFixed(0)}px;
  position: relative;
}
.mm-loader-ellipsis div {
  position: absolute; width: ${(sz * 0.2).toFixed(0)}px;
  height: ${(sz * 0.2).toFixed(0)}px;
  border-radius: 50%; background: ${clr};
  top: 50%; transform: translateY(-50%);
}
.mm-loader-ellipsis div:nth-child(1) { left: ${(sz * 0.08).toFixed(0)}px; animation: mm-loader-el1 0.6s infinite; }
.mm-loader-ellipsis div:nth-child(2) { left: ${(sz * 0.08).toFixed(0)}px; animation: mm-loader-el2 0.6s infinite; }
.mm-loader-ellipsis div:nth-child(3) { left: ${(sz * 0.35).toFixed(0)}px; animation: mm-loader-el2 0.6s infinite; animation-delay: -0.3s; }
.mm-loader-ellipsis div:nth-child(4) { left: ${(sz * 0.63).toFixed(0)}px; animation: mm-loader-el3 0.6s infinite; }
@keyframes mm-loader-el1 { 0% { transform: scale(0) translateY(-50%); } 100% { transform: scale(1) translateY(-50%); } }
@keyframes mm-loader-el2 { 0% { transform: translateX(0) translateY(-50%); } 100% { transform: translateX(${(sz * 0.27).toFixed(0)}px) translateY(-50%); } }
@keyframes mm-loader-el3 { 0% { transform: scale(1) translateY(-50%); } 100% { transform: scale(0) translateY(-50%); } }`,
      },
      'grid': {
        html: `<div class="mm-loader-grid">${Array.from({ length: 9 }).map(() => '\n  <div></div>').join('')}
</div>`,
        css: `.mm-loader-grid {
  display: grid; grid-template-columns: 1fr 1fr 1fr;
  gap: ${(sz * 0.06).toFixed(0)}px;
  width: ${sz}px; height: ${sz}px;
}
.mm-loader-grid div {
  background: ${clr}; border-radius: ${(2 * u).toFixed(0)}px;
  animation: mm-loader-grid 1.2s ease-in-out infinite;
}
${Array.from({ length: 9 }).map((_, i) =>
  `.mm-loader-grid div:nth-child(${i + 1}) { animation-delay: ${((i % 3 + Math.floor(i / 3)) * 0.15).toFixed(2)}s; }`
).join('\n')}
@keyframes mm-loader-grid {
  0%, 100% { opacity: 1; } 50% { opacity: 0.3; }
}`,
      },
      'roller': {
        html: `<div class="mm-loader-roller">${Array.from({ length: 6 }).map(() => '\n  <div></div>').join('')}
</div>`,
        css: `.mm-loader-roller {
  width: ${sz}px; height: ${sz}px; position: relative;
  animation: mm-loader-spin 1.2s linear infinite;
}
.mm-loader-roller div {
  position: absolute; width: ${(sz * 0.18 * 0.7).toFixed(0)}px;
  height: ${(sz * 0.18 * 0.7).toFixed(0)}px;
  border-radius: 50%; background: ${clr};
}
${Array.from({ length: 6 }).map((_, i) => {
  const angle = (i / 6) * Math.PI * 2;
  const r = sz * 0.35;
  const cx = sz / 2 + Math.cos(angle) * r - (sz * 0.18 * 0.7) / 2;
  const cy = sz / 2 + Math.sin(angle) * r - (sz * 0.18 * 0.7) / 2;
  return `.mm-loader-roller div:nth-child(${i + 1}) { left: ${cx.toFixed(0)}px; top: ${cy.toFixed(0)}px; opacity: ${(1 - i * 0.14).toFixed(2)}; }`;
}).join('\n')}
@keyframes mm-loader-spin { to { transform: rotate(360deg); } }`,
      },
      'hourglass': {
        html: `<div class="mm-loader-hourglass"></div>`,
        css: `.mm-loader-hourglass {
  width: ${(sz * 0.5).toFixed(0)}px; height: ${(sz * 0.5).toFixed(0)}px;
  border: ${(4 * u).toFixed(1)}px solid ${clr};
  border-color: ${clr} transparent;
  border-radius: 50%; box-sizing: border-box;
  animation: mm-loader-hourglass 1.2s linear infinite;
}
@keyframes mm-loader-hourglass {
  0% { transform: rotate(0); }
  100% { transform: rotate(720deg); }
}`,
      },
      'square-spin': {
        html: `<div class="mm-loader-square-spin"></div>`,
        css: `.mm-loader-square-spin {
  width: ${(sz * 0.5).toFixed(0)}px; height: ${(sz * 0.5).toFixed(0)}px;
  background: ${clr};
  animation: mm-loader-square 1.8s infinite ease-in-out;
}
@keyframes mm-loader-square {
  0% { transform: perspective(120px) rotateX(0) rotateY(0); }
  25% { transform: perspective(120px) rotateX(-180deg) rotateY(0); }
  50% { transform: perspective(120px) rotateX(-180deg) rotateY(-180deg); }
  75% { transform: perspective(120px) rotateX(0) rotateY(-180deg); }
  100% { transform: perspective(120px) rotateX(0) rotateY(0); }
}`,
      },
    };
    return codeMap[id] || { html: '', css: '' };
  };

  const code = getCode();
  const fullCode = `<!-- HTML -->\n${code.html}\n\n/* CSS */\n${code.css}`;

  const copyCode = () => {
    navigator.clipboard.writeText(fullCode);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };

  return (
    <div className="mini-tool">
      <style>{`
        .ldg-grid {
          display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
          margin-bottom: 20px;
        }
        .ldg-cell {
          display: flex; flex-direction: column; align-items: center; justify-content: center;
          gap: 8px; padding: 14px 8px; border-radius: 10px; cursor: pointer;
          border: 2px solid var(--id-border); background: var(--id-surface);
          transition: all 180ms ease; min-height: 80px;
        }
        .ldg-cell:hover { border-color: var(--id-border-strong); background: var(--id-surface-alt); }
        .ldg-cell.active { border-color: var(--id-brand-blue); background: var(--id-brand-blue-soft); }
        .ldg-cell-label {
          font-size: 10px; font-weight: 600; color: var(--id-text-muted);
          text-transform: uppercase; letter-spacing: 0.04em; text-align: center;
        }
        .ldg-preview-box {
          display: flex; align-items: center; justify-content: center;
          padding: 32px; border-radius: 12px;
          background: var(--id-surface-alt); border: 1px solid var(--id-border);
          min-height: 120px; margin-bottom: 16px;
        }
        .ldg-controls { display: grid; grid-template-columns: auto 1fr; gap: 12px 16px; align-items: center; margin-bottom: 16px; }
        .ldg-code {
          font-family: 'JetBrains Mono', monospace; font-size: 12px;
          background: var(--id-surface-alt); border: 1px solid var(--id-border);
          border-radius: 8px; padding: 14px; color: var(--id-text);
          white-space: pre-wrap; word-break: break-all; line-height: 1.6;
          max-height: 240px; overflow-y: auto; resize: vertical;
          width: 100%; box-sizing: border-box; min-height: 100px;
        }
        @media (max-width: 600px) {
          .ldg-grid { grid-template-columns: repeat(3, 1fr); }
        }
      `}</style>

      {/* Preset grid */}
      <label className="mini-label">Choose a loader</label>
      <div className="ldg-grid">
        {LOADERS.map((l) => (
          <div key={l.id} className={`ldg-cell ${selected === l.id ? 'active' : ''}`}
               onClick={() => setSelected(l.id)}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: 40, height: 40 }}>
              {renderLoader(l.id, 32, selected === l.id ? color : 'var(--id-text-muted)')}
            </div>
            <div className="ldg-cell-label">{l.name}</div>
          </div>
        ))}
      </div>

      {/* Large preview */}
      <label className="mini-label">Preview</label>
      <div className="ldg-preview-box">
        {renderLoader(selected, size, color)}
      </div>

      {/* Controls */}
      <div className="ldg-controls">
        <label className="mini-label" style={{ marginBottom: 0 }}>Color</label>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <input type="color" value={color} onChange={(e) => setColor(e.target.value)}
                 style={{ width: 36, height: 32, border: 'none', borderRadius: 6, cursor: 'pointer', padding: 0 }} />
          <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 13, color: 'var(--id-text)' }}>{color}</span>
        </div>

        <label className="mini-label" style={{ marginBottom: 0 }}>Size</label>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <input type="range" min="20" max="120" value={size}
                 onChange={(e) => setSize(Number(e.target.value))}
                 className="cmp-slider" style={{ flex: 1 }} />
          <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 13, color: 'var(--id-text)', minWidth: 40, textAlign: 'right' }}>{size}px</span>
        </div>
      </div>

      {/* Code output */}
      <label className="mini-label">HTML + CSS</label>
      <textarea className="ldg-code" readOnly value={fullCode} onClick={(e) => e.target.select()} />

      <div className="cmp-actions">
        <button className="btn btn-primary" onClick={copyCode}>
          <window.Icon name={copied ? 'check' : 'doc'} size={16} /> {copied ? 'Copied!' : 'Copy HTML + CSS'}
        </button>
      </div>
    </div>
  );
};
