import { splitTextIntoLines } from '@/application/Common/Text/SplitTextIntoLines';
import type { ICodeBuilder } from './ICodeBuilder';

const TotalFunctionSeparatorChars = 58;

export abstract class CodeBuilder implements ICodeBuilder {
  private readonly lines = new Array<string>();

  // Returns current line starting from 0 (no lines), or 1 (have single line)
  public get currentLine(): number {
    return this.lines.length;
  }

  public appendLine(code?: string): CodeBuilder {
    if (!code) {
      this.lines.push('');
      return this;
    }
    const lines = splitTextIntoLines(code);
    if (lines) {
      this.lines.push(...lines);
    }
    return this;
  }

  public appendTrailingHyphensCommentLine(
    totalRepeatHyphens: number = TotalFunctionSeparatorChars,
  ): CodeBuilder {
    return this.appendCommentLine('-'.repeat(totalRepeatHyphens));
  }

  public appendCommentLine(commentLine?: string): CodeBuilder {
    this.lines.push(`${this.getCommentDelimiter()} ${commentLine}`);
    return this;
  }

  public appendFunction(name: string, code: string): CodeBuilder {
    if (!name) { throw new Error('name cannot be empty or null'); }
    if (!code) { throw new Error('code cannot be empty or null'); }
    return this
      .appendCommentLineWithHyphensAround(name)
      .appendLine(this.writeStandardOut(`--- ${name}`))
      .appendLine(code)
      .appendTrailingHyphensCommentLine();
  }

  public appendCommentLineWithHyphensAround(
    sectionName: string,
    totalRepeatHyphens: number = TotalFunctionSeparatorChars,
  ): CodeBuilder {
    if (!sectionName) { throw new Error('sectionName cannot be empty or null'); }
    if (sectionName.length >= totalRepeatHyphens) {
      return this.appendCommentLine(sectionName);
    }
    const firstHyphens = '-'.repeat(Math.floor((totalRepeatHyphens - sectionName.length) / 2));
    const secondHyphens = '-'.repeat(Math.ceil((totalRepeatHyphens - sectionName.length) / 2));
    return this
      .appendTrailingHyphensCommentLine()
      .appendCommentLine(firstHyphens + sectionName + secondHyphens)
      .appendTrailingHyphensCommentLine(TotalFunctionSeparatorChars);
  }

  public toString(): string {
    return this.lines.join(this.getNewLineTerminator());
  }

  protected abstract getCommentDelimiter(): string;

  protected abstract writeStandardOut(text: string): string;

  protected abstract getNewLineTerminator(): string;
}
