// Server-side minimal ePOS-Print XML builder for Epson printers
// Focused on printer-only tags. Builds the inner message for <epos-print>.

function escapeXml(str) {
  return String(str)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/\"/g, "&quot;")
    .replace(/'/g, "&apos;");
}

class EposMessageBuilder {
  constructor() {
    this.parts = [];
  }

  // Text and styles
  text(content) { this.parts.push(`<text>${escapeXml(content)}</text>`); return this; }
  textLang(lang) { this.parts.push(`<text lang="${lang}"/>`); return this; }
  textAlign(align) { this.parts.push(`<text align="${align}"/>`); return this; }
  textRotate(rotate) { this.parts.push(`<text rotate="${rotate ? 'true' : 'false'}"/>`); return this; }
  textLineSpace(linespc) { this.parts.push(`<text linespc="${linespc}"/>`); return this; }
  textFont(font) { this.parts.push(`<text font="${font}"/>`); return this; }
  textSmooth(smooth) { this.parts.push(`<text smooth="${smooth ? 'true' : 'false'}"/>`); return this; }
  textDouble(dw, dh) {
    const attrs = [dw !== undefined ? `dw="${dw ? 'true' : 'false'}"` : '', dh !== undefined ? `dh="${dh ? 'true' : 'false'}"` : ''].filter(Boolean).join(' ');
    this.parts.push(`<text ${attrs}/>`.trim());
    return this;
  }
  textSize(width, height) {
    const attrs = [width !== undefined ? `width="${width}"` : '', height !== undefined ? `height="${height}"` : ''].filter(Boolean).join(' ');
    this.parts.push(`<text ${attrs}/>`.trim());
    return this;
  }
  textStyle({ reverse, ul, em, color } = {}) {
    const attrs = [];
    if (reverse !== undefined) attrs.push(`reverse="${reverse ? 'true' : 'false'}"`);
    if (ul !== undefined) attrs.push(`ul="${ul ? 'true' : 'false'}"`);
    if (em !== undefined) attrs.push(`em="${em ? 'true' : 'false'}"`);
    if (color !== undefined) attrs.push(`color="${color}"`);
    this.parts.push(`<text ${attrs.join(' ')}/>`.trim());
    return this;
  }
  textPosition(x) { this.parts.push(`<text x="${x}"/>`); return this; }
  textVPosition(y) { this.parts.push(`<text y="${y}"/>`); return this; }

  // Feed
  feed() { this.parts.push('<feed/>'); return this; }
  feedUnit(unit) { this.parts.push(`<feed unit="${unit}"/>`); return this; }
  feedLine(line) { this.parts.push(`<feed line="${line}"/>`); return this; }
  feedPosition(pos) { this.parts.push(`<feed pos="${pos}"/>`); return this; }

  // Cut
  cut(type) { this.parts.push(`<cut type="${type}"/>`); return this; }

  // Drawer
  pulse({ drawer = 'drawer_1', time = 'pulse_200' } = {}) { this.parts.push(`<pulse drawer="${drawer}" time="${time}"/>`); return this; }

  // Barcode and symbols (minimal)
  barcode(data, { type, hri, font, width, height } = {}) {
    const attrs = [];
    if (type) attrs.push(`type="${type}"`);
    if (hri) attrs.push(`hri="${hri}"`);
    if (font) attrs.push(`font="${font}"`);
    if (width) attrs.push(`width="${width}"`);
    if (height) attrs.push(`height="${height}"`);
    this.parts.push(`<barcode ${attrs.join(' ')}>${escapeXml(data)}</barcode>`.trim());
    return this;
  }
  qrcode(data, { model = 'qrcode_model_2', level = 'level_m', size } = {}) {
    const attrs = [`type="${model}"`, `level="${level}"`];
    if (size) attrs.push(`size="${size}"`);
    this.parts.push(`<symbol ${attrs.join(' ')}>${escapeXml(data)}</symbol>`);
    return this;
  }

  // Logo (NV) and image are omitted for now; can be added later.

  build() {
    return this.parts.join('');
  }
}

// Accepts a list of operations: [{ op: 'text', args: {...} | [] }, ...]
function buildFromOperations(ops) {
  const b = new EposMessageBuilder();
  for (const item of ops || []) {
    const { op } = item;
    if (!op) continue;
    switch (op) {
      case 'text': b.text(item.value ?? ''); break;
      case 'textLang': b.textLang(item.lang); break;
      case 'textAlign': b.textAlign(item.align); break;
      case 'textRotate': b.textRotate(!!item.rotate); break;
      case 'textLineSpace': b.textLineSpace(item.linespc); break;
      case 'textFont': b.textFont(item.font); break;
      case 'textSmooth': b.textSmooth(!!item.smooth); break;
      case 'textDouble': b.textDouble(item.dw, item.dh); break;
      case 'textSize': b.textSize(item.width, item.height); break;
      case 'textStyle': b.textStyle({ reverse: item.reverse, ul: item.ul, em: item.em, color: item.color }); break;
      case 'textPosition': b.textPosition(item.x); break;
      case 'textVPosition': b.textVPosition(item.y); break;
      case 'feed': b.feed(); break;
      case 'feedUnit': b.feedUnit(item.unit); break;
      case 'feedLine': b.feedLine(item.line); break;
      case 'feedPosition': b.feedPosition(item.pos); break;
      case 'cut': b.cut(item.type || 'feed'); break;
      case 'pulse': b.pulse({ drawer: item.drawer, time: item.time }); break;
      case 'barcode': b.barcode(item.data || '', { type: item.type, hri: item.hri, font: item.font, width: item.width, height: item.height }); break;
      case 'qrcode': b.qrcode(item.data || '', { model: item.model, level: item.level, size: item.size }); break;
      default:
        // ignore unknown for now
        break;
    }
  }
  return b.build();
}

module.exports = {
  EposMessageBuilder,
  buildFromOperations,
};

