import { components } from '@octokit/openapi-types';

export function timeHelper(seconds: number): string {
  return `${seconds.toFixed(3)}s`;
}

export abstract class Meta {
  title: string;
  duration = 0;

  constructor(title: string) {
    this.title = title;
  }

  abstract get summary(): string;

  abstract get mark(): string;
}

export type Annotation = components['schemas']['check-annotation'];

export class RunMeta extends Meta {
  total = 0;
  passed = 0;
  skipped = 0;
  failed = 0;

  tests: TestMeta[] = [];
  suites: RunMeta[] = [];

  extractAnnotations(): Annotation[] {
    const result = [] as Annotation[];
    for (const suite of this.suites) {
      result.push(...suite.extractAnnotations());
    }
    for (const test of this.tests) {
      if (test.annotation !== undefined) {
        result.push(test.annotation);
      }
    }
    return result;
  }

  addTests(testSuite: TestMeta[]): void {
    for (const test of testSuite) {
      this.addTest(test);
    }
  }

  addTest(test: TestMeta): void {
    if (test.suite === undefined) {
      return;
    }
    if (test.suite === this.title) {
      this.total++;
      this.duration += test.duration;
      this.tests.push(test);
      if (test.result === 'Passed') this.passed++;
      else if (test.result === 'Failed') this.failed++;
      else this.skipped++;
      return;
    }

    let target = this.suites.find(s => s.title === test.suite);
    if (target === undefined) {
      target = new RunMeta(test.suite);
      this.suites.push(target);
    }

    target.addTest(test);
  }

  get summary(): string {
    const result = this.failed > 0 ? 'Failed' : 'Passed';
    const sPart = this.skipped > 0 ? `, skipped: ${this.skipped}` : '';
    const fPart = this.failed > 0 ? `, failed: ${this.failed}` : '';
    const dPart = ` in ${timeHelper(this.duration)}`;
    return `${this.mark} ${this.title} - ${this.passed}/${this.total}${sPart}${fPart} - ${result}${dPart}`;
  }

  get mark(): string {
    if (this.failed > 0) return '❌️';
    else if (this.skipped === 0) return '✅';
    return '⚠️';
  }
}

export class TestMeta extends Meta {
  suite: string;
  result: string | undefined;
  annotation: Annotation | undefined;

  constructor(suite: string, title: string) {
    super(title);
    this.suite = suite;
    this.result = undefined;
    this.duration = Number.NaN;
  }

  isSkipped(): boolean {
    return this.result === 'Skipped';
  }

  isFailed(): boolean {
    return this.result === 'Failed';
  }

  get summary(): string {
    const dPart = this.isSkipped() ? '' : ` in ${timeHelper(this.duration)}`;
    return `${this.mark} **${this.title}** - ${this.result}${dPart}`;
  }

  get mark(): string {
    if (this.isFailed()) return '❌️';
    else if (this.isSkipped()) return '⚠️';
    return '✅';
  }
}
