'use strict';

const readline = require('readline');
const { gray } = require('../utils/colors');

const FRAMES = ['⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];

class Spinner {
  constructor(indent = '', leadingLines = 0) {
    this.timer = null;
    this.index = 0;
    this.textProvider = () => '';
    this.active = false;
    this.indent = indent;
    this.leadingLines = Math.max(0, Number(leadingLines) || 0);
    this.leadingWritten = false;
    this.thinkingLineReady = false;
  }

  setIndent(indent) {
    this.indent = indent || '';
  }

  start(textProvider) {
    this.textProvider = textProvider || (() => '');
    this.active = true;
    this.thinkingLineReady = false;
    if (this.leadingLines > 0 && !this.leadingWritten) {
      process.stdout.write('\n'.repeat(this.leadingLines));
      this.leadingWritten = true;
    }
    this.render();
    this.timer = setInterval(() => this.render(), 120);
  }

  ensureThinkingLine() {
    if (this.thinkingLineReady) return;
    process.stdout.write('\n');
    this.thinkingLineReady = true;
    readline.moveCursor(process.stdout, 0, -1);
    readline.cursorTo(process.stdout, 0);
  }

  render() {
    readline.clearLine(process.stdout, 0);
    readline.cursorTo(process.stdout, 0);
    const frame = FRAMES[this.index % FRAMES.length];
    this.index += 1;
    const provided = this.textProvider(frame);
    let suffix = '';
    let thinking = '';
    let colorThinking = false;
    let hasThinkingLine = false;
    if (typeof provided === 'string') {
      suffix = provided;
    } else if (provided && typeof provided === 'object') {
      suffix = provided.label || '';
      thinking = provided.thinking || '';
      colorThinking = !!provided.colorThinking;
      hasThinkingLine = Object.prototype.hasOwnProperty.call(provided, 'thinking');
    }
    const linePrefix = `${this.indent}${frame}${suffix}`;
    process.stdout.write(linePrefix);
    if (hasThinkingLine) {
      this.ensureThinkingLine();
      const width = process.stdout.columns || 80;
      let visibleThinking = thinking;
      const maxThinking = Math.max(0, width - this.indent.length - 1);
      if (visibleThinking && maxThinking > 0 && visibleThinking.length > maxThinking) {
        visibleThinking = visibleThinking.slice(0, maxThinking);
      }
      if (visibleThinking && maxThinking === 0) visibleThinking = '';
      const line = visibleThinking ? (colorThinking ? gray(visibleThinking) : visibleThinking) : '';
      const leadSpaces = (suffix.match(/^\s*/) || [''])[0].length;
      const alignCol = this.indent.length + frame.length + leadSpaces;
      readline.moveCursor(process.stdout, 0, 1);
      readline.cursorTo(process.stdout, alignCol);
      readline.clearLine(process.stdout, 0);
      process.stdout.write(line);
      readline.moveCursor(process.stdout, 0, -1);
      readline.cursorTo(process.stdout, 0);
    }
  }

  stop(finalText) {
    if (this.timer) clearInterval(this.timer);
    this.timer = null;
    this.active = false;
    readline.clearLine(process.stdout, 0);
    readline.cursorTo(process.stdout, 0);
    const provided = this.textProvider('');
    let thinking = '';
    let colorThinking = false;
    let hasThinkingLine = false;
    if (provided && typeof provided === 'object' && Object.prototype.hasOwnProperty.call(provided, 'thinking')) {
      thinking = provided.thinking || '';
      colorThinking = !!provided.colorThinking;
      hasThinkingLine = true;
    }
    const linePrefix = `${this.indent}${finalText}`;
    process.stdout.write(linePrefix);
    if (hasThinkingLine) {
      this.ensureThinkingLine();
      const width = process.stdout.columns || 80;
      let visibleThinking = thinking;
      const maxThinking = Math.max(0, width - this.indent.length - 1);
      if (visibleThinking && maxThinking > 0 && visibleThinking.length > maxThinking) {
        visibleThinking = visibleThinking.slice(0, maxThinking);
      }
      if (visibleThinking && maxThinking === 0) visibleThinking = '';
      const line = visibleThinking ? (colorThinking ? gray(visibleThinking) : visibleThinking) : '';
      let alignCol = this.indent.length;
      const firstNonSpace = finalText.search(/\S/);
      if (firstNonSpace >= 0) {
        const afterFirst = finalText.slice(firstNonSpace + 1);
        const spaceAfter = (afterFirst.match(/^\s*/) || [''])[0].length;
        alignCol = this.indent.length + firstNonSpace + 1 + spaceAfter;
      }
      readline.moveCursor(process.stdout, 0, 1);
      readline.cursorTo(process.stdout, alignCol);
      readline.clearLine(process.stdout, 0);
      process.stdout.write(line);
      process.stdout.write('\n');
    } else {
      process.stdout.write('\n');
    }
    this.thinkingLineReady = false;
  }

  stopSilent() {
    if (this.timer) clearInterval(this.timer);
    this.timer = null;
    this.active = false;
    this.thinkingLineReady = false;
    readline.clearLine(process.stdout, 0);
    readline.cursorTo(process.stdout, 0);
  }
}

function truncateThinking(text, max = 50) {
  const sanitized = String(text || '').replace(/[\r\n]+/g, ' ').replace(/\s+/g, ' ').trim();
  if (sanitized.length <= max) return sanitized;
  return sanitized.slice(0, max) + '...';
}

function formatThinkingLine(text) {
  if (!text) return '';
  return gray(truncateThinking(text));
}

module.exports = { Spinner, formatThinkingLine, truncateThinking };
