// Caption Formatter — convert normal text into Unicode fancy text styles
// for social media (Instagram, X, LinkedIn bios/captions).

window.TOOL_HANDLERS['caption-formatter'] = function CaptionFormatterTool() {
  const [text, setText] = React.useState('Hello World');
  const [copiedId, setCopiedId] = React.useState(null);

  // ── Unicode mapping tables ──────────────────────────────────────────

  // Build an offset-based mapper for Mathematical Alphanumeric Symbols.
  // Takes separate starting code points for uppercase A, lowercase a, and digit 0.
  function makeOffsetMapper(upperStart, lowerStart, digitStart) {
    return function (ch) {
      const code = ch.codePointAt(0);
      if (code >= 65 && code <= 90 && upperStart != null) {
        return String.fromCodePoint(upperStart + (code - 65));
      }
      if (code >= 97 && code <= 122 && lowerStart != null) {
        return String.fromCodePoint(lowerStart + (code - 97));
      }
      if (code >= 48 && code <= 57 && digitStart != null) {
        return String.fromCodePoint(digitStart + (code - 48));
      }
      return ch;
    };
  }

  // Mathematical Bold: U+1D400 (A) / U+1D41A (a) / U+1D7CE (0)
  const boldMap = makeOffsetMapper(0x1D400, 0x1D41A, 0x1D7CE);

  // Mathematical Italic: U+1D434 (A) / U+1D44E (a) — italic has no digits, use normal
  // Exception: h -> U+210E (Planck constant)
  const italicMapRaw = makeOffsetMapper(0x1D434, 0x1D44E, null);
  const italicMap = function (ch) {
    if (ch === 'h') return '\u210E';
    return italicMapRaw(ch);
  };

  // Mathematical Bold Italic: U+1D468 (A) / U+1D482 (a) — no digits, use bold digits
  const boldItalicMapRaw = makeOffsetMapper(0x1D468, 0x1D482, 0x1D7CE);
  const boldItalicMap = function (ch) { return boldItalicMapRaw(ch); };

  // Mathematical Monospace: U+1D670 (A) / U+1D68A (a) / U+1D7F6 (0)
  const monoMap = makeOffsetMapper(0x1D670, 0x1D68A, 0x1D7F6);

  // Mathematical Script: U+1D49C (A) / U+1D4B6 (a) — no digits
  // Exceptions: B->U+212C, E->U+2130, F->U+2131, H->U+210B, I->U+2110, L->U+2112,
  //             M->U+2133, R->U+211B, e->U+212F, g->U+210A, o->U+2134
  const scriptExceptions = {
    'B': '\u212C', 'E': '\u2130', 'F': '\u2131', 'H': '\u210B',
    'I': '\u2110', 'L': '\u2112', 'M': '\u2133', 'R': '\u211B',
    'e': '\u212F', 'g': '\u210A', 'o': '\u2134'
  };
  const scriptMapRaw = makeOffsetMapper(0x1D49C, 0x1D4B6, null);
  const scriptMap = function (ch) {
    if (scriptExceptions[ch]) return scriptExceptions[ch];
    return scriptMapRaw(ch);
  };

  // Mathematical Bold Script: U+1D4D0 (A) / U+1D4EA (a) — no digits, use bold digits
  const boldScriptMap = makeOffsetMapper(0x1D4D0, 0x1D4EA, 0x1D7CE);

  // Mathematical Fraktur: U+1D504 (A) / U+1D51E (a) — no digits
  // Exceptions: C->U+212D, H->U+210C, I->U+2111, R->U+211C, Z->U+2128
  const frakturExceptions = {
    'C': '\u212D', 'H': '\u210C', 'I': '\u2111', 'R': '\u211C', 'Z': '\u2128'
  };
  const frakturMapRaw = makeOffsetMapper(0x1D504, 0x1D51E, null);
  const frakturMap = function (ch) {
    if (frakturExceptions[ch]) return frakturExceptions[ch];
    return frakturMapRaw(ch);
  };

  // Mathematical Double-Struck: U+1D538 (A) / U+1D552 (a) / U+1D7D8 (0)
  // Exceptions: C->U+2102, H->U+210D, N->U+2115, P->U+2119, Q->U+211A, R->U+211D, Z->U+2124
  const dblStruckExceptions = {
    'C': '\u2102', 'H': '\u210D', 'N': '\u2115', 'P': '\u2119',
    'Q': '\u211A', 'R': '\u211D', 'Z': '\u2124'
  };
  const dblStruckMapRaw = makeOffsetMapper(0x1D538, 0x1D552, 0x1D7D8);
  const dblStruckMap = function (ch) {
    if (dblStruckExceptions[ch]) return dblStruckExceptions[ch];
    return dblStruckMapRaw(ch);
  };

  // Circled letters: Ⓐ=U+24B6..Ⓩ=U+24CF (upper), ⓐ=U+24D0..ⓩ=U+24E9 (lower), ⓪=U+24EA, ①=U+2460..⑨=U+2468 (digits)
  function circledMap(ch) {
    var code = ch.codePointAt(0);
    if (code >= 65 && code <= 90) return String.fromCodePoint(0x24B6 + (code - 65));
    if (code >= 97 && code <= 122) return String.fromCodePoint(0x24D0 + (code - 97));
    if (ch === '0') return String.fromCodePoint(0x24EA);
    if (code >= 49 && code <= 57) return String.fromCodePoint(0x2460 + (code - 49));
    return ch;
  }

  // Squared letters (Negative Squared): 🄰=U+1F130..🅉=U+1F149 (upper only), digits not available
  function squaredMap(ch) {
    var code = ch.codePointAt(0);
    if (code >= 65 && code <= 90) return String.fromCodePoint(0x1F130 + (code - 65));
    if (code >= 97 && code <= 122) return String.fromCodePoint(0x1F130 + (code - 97));
    return ch;
  }

  // Small Caps — manual mapping via Latin Extended / Phonetic Extensions
  var smallCapsTable = {
    'a': '\u1D00', 'b': '\u0299', 'c': '\u1D04', 'd': '\u1D05',
    'e': '\u1D07', 'f': '\uA730', 'g': '\u0262', 'h': '\u029C',
    'i': '\u026A', 'j': '\u1D0A', 'k': '\u1D0B', 'l': '\u029F',
    'm': '\u1D0D', 'n': '\u0274', 'o': '\u1D0F', 'p': '\u1D18',
    'q': '\u01EB', 'r': '\u0280', 's': '\uA731', 't': '\u1D1B',
    'u': '\u1D1C', 'v': '\u1D20', 'w': '\u1D21', 'x': '\u02E3',
    'y': '\u028F', 'z': '\u1D22'
  };
  function smallCapsMap(ch) {
    var code = ch.codePointAt(0);
    // uppercase stays uppercase
    if (code >= 65 && code <= 90) return ch;
    var lower = ch.toLowerCase();
    if (smallCapsTable[lower]) return smallCapsTable[lower];
    return ch;
  }

  // Fullwidth: ! = U+FF01 (offset from U+0021), space = U+3000
  function fullwidthMap(ch) {
    var code = ch.codePointAt(0);
    if (code >= 0x21 && code <= 0x7E) return String.fromCodePoint(0xFF01 + (code - 0x21));
    if (ch === ' ') return '\u3000';
    return ch;
  }

  // Combining-character styles (strikethrough, underline)
  function combiningMapper(combiningChar) {
    return function (ch) {
      return ch + combiningChar;
    };
  }
  var strikethroughMap = combiningMapper('\u0336');
  var underlineMap = combiningMapper('\u0332');

  // ── Apply a mapper function to each character of the text ──────────

  function applyStyle(input, mapper) {
    var result = '';
    for (var i = 0; i < input.length; i++) {
      var ch = input[i];
      var code = ch.codePointAt(0);
      // Handle surrogate pairs
      if (code > 0xFFFF) {
        i++;
      }
      // Only transform ASCII letters and digits; pass everything else through
      var isLetter = (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
      var isDigit = code >= 48 && code <= 57;
      if (isLetter || isDigit) {
        result += mapper(ch);
      } else {
        result += ch;
      }
    }
    return result;
  }

  // ── Style definitions ──────────────────────────────────────────────

  var styles = [
    { id: 'bold',          label: 'Bold',          mapper: boldMap },
    { id: 'italic',        label: 'Italic',        mapper: italicMap },
    { id: 'bold-italic',   label: 'Bold Italic',   mapper: boldItalicMap },
    { id: 'monospace',     label: 'Monospace',      mapper: monoMap },
    { id: 'script',        label: 'Script',         mapper: scriptMap },
    { id: 'bold-script',   label: 'Bold Script',    mapper: boldScriptMap },
    { id: 'fraktur',       label: 'Fraktur',        mapper: frakturMap },
    { id: 'double-struck', label: 'Double-Struck',  mapper: dblStruckMap },
    { id: 'circled',       label: 'Circled',         mapper: circledMap },
    { id: 'squared',       label: 'Squared',         mapper: squaredMap },
    { id: 'small-caps',    label: 'Small Caps',      mapper: smallCapsMap },
    { id: 'fullwidth',     label: 'Full Width',      mapper: fullwidthMap },
    { id: 'strikethrough', label: 'Strikethrough',   mapper: strikethroughMap },
    { id: 'underline',     label: 'Underline',       mapper: underlineMap },
  ];

  // ── Copy to clipboard ─────────────────────────────────────────────

  function copyToClipboard(styledText, styleId) {
    navigator.clipboard.writeText(styledText).then(function () {
      setCopiedId(styleId);
      setTimeout(function () { setCopiedId(null); }, 1500);
    });
  }

  // ── Render ─────────────────────────────────────────────────────────

  var inputText = text || '';

  return (
    <div className="mini-tool">
      <label className="mini-label">Your text</label>
      <textarea
        className="mini-input mini-textarea"
        style={{ minHeight: 100 }}
        placeholder="Type your caption here..."
        value={text}
        onChange={function (e) { setText(e.target.value); }}
      />

      <div className="cmp-meta" style={{ marginTop: 8, marginBottom: 16 }}>
        Click any style to copy. Works on Instagram, X, LinkedIn, TikTok, and more.
      </div>

      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))',
        gap: 10
      }}>
        {styles.map(function (style) {
          var styled = inputText ? applyStyle(inputText, style.mapper) : '';
          var isCopied = copiedId === style.id;

          return (
            <div
              key={style.id}
              onClick={function () { if (styled) copyToClipboard(styled, style.id); }}
              style={{
                background: 'var(--id-surface-alt)',
                border: isCopied ? '1.5px solid var(--id-brand-blue)' : '1px solid var(--id-border)',
                borderRadius: 12,
                padding: '12px 14px',
                cursor: styled ? 'pointer' : 'default',
                transition: 'border-color 180ms, box-shadow 180ms',
                boxShadow: isCopied ? 'var(--id-shadow-focus)' : 'none',
                display: 'flex',
                flexDirection: 'column',
                gap: 8,
                minHeight: 70,
                position: 'relative'
              }}
            >
              <div style={{
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'space-between',
                gap: 8
              }}>
                <span style={{
                  fontSize: 11,
                  fontWeight: 700,
                  textTransform: 'uppercase',
                  letterSpacing: '0.06em',
                  color: 'var(--id-text-muted)'
                }}>
                  {style.label}
                </span>

                <button
                  className="btn btn-secondary"
                  onClick={function (e) {
                    e.stopPropagation();
                    if (styled) copyToClipboard(styled, style.id);
                  }}
                  disabled={!styled}
                  style={{
                    padding: '4px 10px',
                    fontSize: 12,
                    borderRadius: 8,
                    display: 'inline-flex',
                    alignItems: 'center',
                    gap: 4
                  }}
                >
                  <window.Icon name={isCopied ? 'check' : 'doc'} size={12} />
                  {isCopied ? 'Copied!' : 'Copy'}
                </button>
              </div>

              <div style={{
                fontSize: 15,
                lineHeight: 1.5,
                color: 'var(--id-text)',
                wordBreak: 'break-word',
                overflow: 'hidden',
                display: '-webkit-box',
                WebkitLineClamp: 3,
                WebkitBoxOrient: 'vertical'
              }}>
                {styled || <span style={{ color: 'var(--id-text-muted)', fontStyle: 'italic' }}>Type something above...</span>}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};
