import axiosRetry from 'axios-retry';
import axios from 'axios';

interface TestrailInfo {
  testrailRunId: number;
  testrailDomain: string;
  testrailUsername: string;
  testrailPassword: string;
}

export class TestrailUtility {
  static verifyTestrailIdIsPresent() {
    cy.allure().logStep('Verify testrail id is present');
    const testData = Cypress.currentTest.title;
    const trimmedTitle = testData.trim();
    if (testData === 'An uncaught error was detected outside of a test') {
      return;
    }
    if (trimmedTitle.includes(':')) {
      const index = trimmedTitle.indexOf(':');
      const caseIds = trimmedTitle.substring(0, index + 1);
      const splitted = caseIds.split(' ');

      const regexp = new RegExp('^[C][0-9]*[:]$');
      const regexpr = new RegExp('^[C][0-9]+$');

      if (splitted.length == 1 && !regexp.test(splitted[0])) {
        throw new Error('Test fails because testrail id is not properly formatted');
      } else if (splitted.length > 1) {
        for (let i = 0; i < splitted.length - 1; i++) {
          if (!regexpr.test(splitted[i])) {
            throw new Error('Test fails because testrail id is not properly formatted');
          }
        }
        if (!regexp.test(splitted[splitted.length - 1])) {
          throw new Error('Test fails because testrail id is not properly formatted');
        }
      } else if (splitted.length == 0) {
        throw new Error(
          'Test fails because testrail id is not present or not properly formatted'
        );
      }
      cy.log('Testrail id is: ' + caseIds);
    } else {
      throw new Error(
        'Test fails because testrail id is not present or not properly formatted'
      );
    }
  }

  static async sendResultForCases(postData: any, testrailInfo: TestrailInfo) {
    const { testrailRunId, testrailDomain, testrailUsername, testrailPassword } =
      testrailInfo;
    axiosRetry(axios, {
      retries: 3,
      retryDelay: (retryCount) => {
        console.log(`TestRail sending status error => retry attempt: ${retryCount}`);
        return retryCount * 2000; // time interval between retries
      },
      retryCondition: (error) => {
        return error?.response?.status === 503;
      }
    });
    await axios({
      url: `https://${testrailDomain}/index.php?/api/v2/add_results_for_cases/${testrailRunId}`,
      headers: {
        'Content-Type': 'application/json'
      },
      auth: {
        username: testrailUsername,
        password: testrailPassword
      },
      method: 'POST',
      data: JSON.stringify(postData)
    })
      .then((response) => {
        console.info(
          `Statuses were successfully sent to TestRail: ${response.status} : ${response.statusText}`
        );
      })
      .catch(function (error) {
        if (error.response) {
          // The request was made and the server responded with a status code
          // that falls out of the range of 2xx
          console.info('Data sent to TestRail: ', postData);
          console.error(
            `TestRail sending status error:  ${error.response.status} : "${error.response.data.error}"`
          );
        } else if (error.request) {
          // The request was made but no response was received
          // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
          // http.ClientRequest in node.js
          console.error(error.request);
        } else {
          // Something happened in setting up the request that triggered an Error
          console.error('Error', error.message);
        }
      });
  }

  static async testRailStatusReporter(tests: any, testrailInfo: TestrailInfo) {
    if (testrailInfo.testrailRunId && testrailInfo.testrailDomain) {
      const testStatuses: any[] = [];
      const testIds: string[][] = [];
      let testRailStatus: number;
      let trimmedTitle: string;
      let index: number;
      let caseIds: string;
      let splitted = [];
      tests.forEach((element: any) => {
        switch (element.state) {
          case 'passed':
            testRailStatus = 1;
            break;
          case 'failed':
            testRailStatus = 5;
            break;
          case 'pending':
            testRailStatus = 7;
            break;
          case 'skipped':
            testRailStatus = 2;
            break;
        }

        testStatuses.push(testRailStatus);

        trimmedTitle = element.title[1].trim();
        index = trimmedTitle.indexOf(':');
        caseIds = trimmedTitle.substring(0, index);
        splitted = caseIds.split(' ');
        splitted.forEach((element, index) => {
          splitted[index] = element.replace('C', '');
        });
        testIds.push(splitted);
      });
      const postData: {
        results: any[];
      } = {
        results: []
      };
      testIds.forEach((element, index) => {
        element.forEach((caseId) => {
          const resultEntry = {
            case_id: caseId,
            status_id: testStatuses[index]
          };
          postData.results.push(resultEntry);
        });
      });

      await TestrailUtility.sendResultForCases(postData, testrailInfo);
    }
  }
}
