class TerminalView {
  constructor(element) {
    this.el = element;
    this.lines = [];
    this.renderPending = false;
    this.autoScroll = true;

    // Track scroll position to determine auto-scroll
    const container = this.el.parentElement;
    container.addEventListener('scroll', () => {
      const atBottom =
        container.scrollHeight - container.scrollTop - container.clientHeight < 30;
      this.autoScroll = atBottom;
    });
  }

  setContent(lines) {
    this.lines = lines;
    this.scheduleRender();
  }

  applyDiff(patches) {
    for (const patch of patches) {
      this.lines.splice(patch.startLine, patch.deleteCount, ...patch.insertLines);
    }
    this.scheduleRender();
  }

  scheduleRender() {
    if (this.renderPending) return;
    this.renderPending = true;
    requestAnimationFrame(() => {
      this.render();
      this.renderPending = false;
    });
  }

  isQrLine(line) {
    // Detect QR code lines: mostly Unicode block characters (▀▄█)
    const blockChars = (line.match(/[\u2580-\u2588]/g) || []).length;
    const nonSpace = line.replace(/\s/g, '').length;
    return nonSpace > 4 && blockChars / nonSpace > 0.3;
  }

  render() {
    const output = [];
    let i = 0;
    while (i < this.lines.length) {
      if (this.isQrLine(this.lines[i])) {
        // Collect all consecutive QR lines
        const qrBlock = [];
        while (i < this.lines.length && this.isQrLine(this.lines[i])) {
          qrBlock.push(this.lines[i]);
          i++;
        }
        // Calculate font-size so QR block fits container width without clipping
        const maxLen = Math.max(...qrBlock.map(l => l.length));
        const containerWidth = (this.el.parentElement?.clientWidth || 375) - 32;
        // monospace char width ≈ 0.62 × font-size
        const fontSize = Math.max(3, Math.floor(containerWidth / (maxLen * 0.62)));
        for (const qline of qrBlock) {
          const esc = qline
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
          output.push(`<span class="qr-line" style="font-size:${fontSize}px">${esc}</span>`);
        }
      } else {
        output.push(this.highlightLine(this.lines[i]));
        i++;
      }
    }
    const html = output.join('\n');
    this.el.innerHTML = html;

    if (this.autoScroll) {
      const container = this.el.parentElement;
      container.scrollTop = container.scrollHeight;
    }
  }

  highlightLine(line) {
    // Escape HTML entities first
    let escaped = line
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');

    // Apply highlighting patterns (order matters — more specific first)

    // Diff: added lines (starts with +)
    if (/^\+[^+]/.test(line)) {
      return `<span class="hl-added">${escaped}</span>`;
    }

    // Diff: removed lines (starts with -)
    if (/^-[^-]/.test(line)) {
      return `<span class="hl-removed">${escaped}</span>`;
    }

    // Tool use markers (blue circle)
    escaped = escaped.replace(
      /(\u23FA|\u25CF|\u2B24)/g,
      '<span class="hl-tool">$1</span>'
    );

    // Thinking markers
    escaped = escaped.replace(
      /(\u273B)/g,
      '<span class="hl-thinking">$1</span>'
    );

    // Output indent marker
    escaped = escaped.replace(
      /(\u23BF)/g,
      '<span class="hl-output">$1</span>'
    );

    // Prompt marker
    escaped = escaped.replace(
      /(\u276F)/g,
      '<span class="hl-prompt">$1</span>'
    );

    // Success markers
    escaped = escaped.replace(
      /(\u2713|\u2714|passed|PASS)/g,
      '<span class="hl-success">$1</span>'
    );

    // Error markers
    escaped = escaped.replace(
      /(\u2717|\u2718|error|ERROR|FAIL|failed)/g,
      '<span class="hl-error">$1</span>'
    );

    // Box drawing characters
    escaped = escaped.replace(
      /([\u2500-\u257F\u250C\u2510\u2514\u2518\u251C\u2524\u252C\u2534\u253C]+)/g,
      '<span class="hl-box">$1</span>'
    );

    // File paths (simplified: word containing / with file extension)
    escaped = escaped.replace(
      /(?<!\w)((?:\.?\.?\/)?(?:[\w.-]+\/)+[\w.-]+\.[\w]+)/g,
      '<span class="hl-path">$1</span>'
    );

    // Line numbers in context (e.g., "  123 |" or ":42:")
    escaped = escaped.replace(
      /^(\s*\d+\s*[|:])/,
      '<span class="hl-linenum">$1</span>'
    );

    return escaped;
  }

  scrollToBottom() {
    const container = this.el.parentElement;
    container.scrollTop = container.scrollHeight;
    this.autoScroll = true;
  }

  clear() {
    this.lines = [];
    this.el.innerHTML = '';
  }
}

window.TerminalView = TerminalView;
