import WDIOReporter, { RunnerStats, TestStats } from "@wdio/reporter";
import type { Reporters } from "@wdio/types";

export class CrabNebulaCloudReporter extends WDIOReporter {
  uploading = false;
  finishedTests: Array<TestStats> = [];

  constructor(options: Partial<Reporters.Options>) {
    options = Object.assign(options, { stdout: true });
    super(options);
  }

  get isSynchronised() {
    return !this.uploading;
  }

  uploadReport(sessionId: string) {
    const remoteWebdriverUrl = process.env.REMOTE_WEBDRIVER_URL;
    if (!remoteWebdriverUrl) {
      return;
    }

    const url = new URL(remoteWebdriverUrl);
    url.pathname += `session/${sessionId}/report`;

    this.uploading = true;
    const upload = async () => {
      const reports = [];
      for (const test of this.finishedTests) {
        const { output, ...stats } = test;
        reports.push(stats);
      }
      this.write("Uploading test report...\n");
      const body = JSON.stringify(reports);
      await fetch(url, {
        method: "POST",
        body,
        headers: {
          "Content-Type": "application/json",
        },
        signal: AbortSignal.timeout(10000),
      }).then((res) => {
        if (res.status !== 200) {
          return res.text();
        }
      });
    };
    upload()
      .then(() => {
        this.write("Test report uploaded\n");
      })
      .catch((err) => {
        this.write(`Failed to upload test report: ${err.message}\n`);
      })
      .finally(() => {
        this.uploading = false;
      });
  }

  onTestPass(testStats: TestStats) {
    this.finishedTests.push(testStats);
  }

  onTestFail(testStats: TestStats) {
    this.finishedTests.push(testStats);
  }

  onRunnerEnd(runnerStats: RunnerStats) {
    if ("sessionId" in runnerStats.capabilities) {
      const sessionId = runnerStats.capabilities.sessionId as string;
      if (sessionId) {
        this.uploadReport(sessionId);
      } else {
        this.write("Invalid session ID found in capabilities\n");
      }
    } else {
      this.write("No session ID found in capabilities\n");
    }
  }
}
