/*

 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



const path = require('path');

const fs = require('fs');

const request = require('sync-request');

const { checkSpelling } = require('./check_spelling');

const { checkAPIDecorators } = require('./check_decorator');

const { checkPermission } = require('./check_permission');

const { checkSyscap } = require('./check_syscap');

const { checkDeprecated } = require('./check_deprecated');

const { checkAPINameOfHump, checkAPIFileName } = require('./check_hump');

const { checkJSDoc } = require('./check_legality');

const { checkNaming } = require('./check_naming');

const { checkEventSubscription } = require('./check_event_subscription');

const { checkAnyInAPI } = require('./check_any');

const { checkFileTagOrder } = require('./check_file_tag_order');

const { hasAPINote, ApiCheckResult, requireTypescriptModule, commentNodeWhiteList, splitPath,

  isWhiteListFile } = require('./utils');

const ts = requireTypescriptModule();

const result = require('../check_result.json');

const rules = require('../code_style_rule.json');

const { checkApiChanges } = require('./check_diff_changes');

const whiteLists = require('../config/jsdocCheckWhiteList.json');



function checkAPICodeStyle(url, isTestCase) {

  if (fs.existsSync(url)) {

    const mdApiFiles = getMdFiles(url, isTestCase);

    tsTransform(mdApiFiles, checkAPICodeStyleCallback);

  }

}



function getMdFiles(url, isTestCase) {

  const mdFiles = [];

  const content = fs.readFileSync(url, 'utf-8');

  const filePathArr = content.split(/[(\r\n)\r\n]+/);

  filePathArr.forEach(filePath => {

    const pathElements = new Set();

    splitPath(filePath, pathElements);

    if (!pathElements.has('build-tools') || isTestCase) {

      mdFiles.push(filePath);

    }

  });

  return mdFiles;

}

exports.getMdFiles = getMdFiles;



function tsTransform(uFiles, callback) {

  uFiles.forEach((filePath, index) => {

    console.log(`scaning file in no ${++index}!`);

    if (/\.d\.ts/.test(filePath) && fs.existsSync(filePath)) {

      const content = fs.readFileSync(filePath, 'utf-8');

      const fileName = path.basename(filePath).replace(/.d.ts/g, '.ts');

      ts.transpileModule(content, {

        compilerOptions: {

          target: ts.ScriptTarget.ES2017,

        },

        fileName: fileName,

        transformers: { before: [callback(filePath)] },

      });

    }

  });

}



function checkAPICodeStyleCallback(fileName) {

  return (context) => {

    return (node) => {

      checkAPIFileName(node, fileName);

      checkAllNode(node, node, fileName);

      return node;

    };

  };

}



function checkAllNode(node, sourcefile, fileName) {

  if (!ts.isImportDeclaration(node) && !ts.isSourceFile(node)) {

    // check hump naming

    checkAPINameOfHump(node, sourcefile, fileName);

  }

  if (hasAPINote(node)) {

    // check decorator

    checkAPIDecorators(node, sourcefile, fileName);

    // check apiNote spelling

    checkSpelling(node, sourcefile, fileName);

    // check syscap

    checkSyscap(node, sourcefile, fileName);

    // check deprecated

    checkDeprecated(node, sourcefile, fileName);

    // check permission

    checkPermission(node, sourcefile, fileName);

    // check event subscription

    checkEventSubscription(node, sourcefile, fileName);

    // check file tag order

    if (ts.isSourceFile(node)) {

      checkFileTagOrder(node, sourcefile, fileName);

    }



    const uesWhiteList = !isWhiteListFile(fileName, whiteLists.JSDocCheck);

    if (commentNodeWhiteList.includes(node.kind) && uesWhiteList) {

      checkJSDoc(node, sourcefile, fileName, true);

    }

  }

  checkAnyInAPI(node, sourcefile, fileName);

  if (ts.isIdentifier(node)) {

    // check variable spelling

    checkSpelling(node, sourcefile, fileName);

    // check naming

    if (node.parent.parent.kind !== ts.SyntaxKind.JSDoc) {

      checkNaming(node, sourcefile, fileName);

    }

  }

  node.getChildren().forEach((item) => checkAllNode(item, sourcefile, fileName));

}



function scanEntry(url, prId, isTestCase) {

  if (prId && prId !== 'NA') {

    checkApiChanges(prId);

    // scan entry

    checkAPICodeStyle(url, isTestCase);

  }

  result.scanResult.push(`api_check: ${ApiCheckResult.formatCheckResult}`);

  return result.scanResult;

}

exports.scanEntry = scanEntry;



function reqGitApi(scanResult, prId, ApiCheckResult) {

  const administrators = new Set();

  const SUCCESS_CODE = 200;

  rules.administrators.forEach((administrator) => {

    administrators.add(administrator.user);

  });

  if (ApiCheckResult || !prId || prId === 'NA') {

    return scanResult;

  }

  const commentRequestPath = `https://gitee.com/api/v5/repos/openharmony/interface_sdk-js/pulls/${prId}/comments?page=1&per_page=100&direction=desc`;

  const res = request('GET', commentRequestPath, {

    headers: {

      'Content-Type': 'application/json;charset=UFT-8',

    },

  });

  if (res.statusCode !== SUCCESS_CODE) {

    throw `The giteeAPI access failed, StatusCode:${res.statusCode}`;

  }

  const resBody = new TextDecoder('utf-8').decode(res.body);

  const comments = JSON.parse(`{"resultBody": ${resBody}}`);

  const resultBody = comments.resultBody;

  if (!resultBody || resultBody.length === 0 || !(resultBody instanceof Array)) {

    throw 'The format of data returned by giteeAPI is incorrect';

  }

  for (let i = 0; i < resultBody.length; i++) {

    const comment = resultBody[i];

    if (!(comment && comment.user && comment.user.id && comment.body)) {

      continue;

    }

    const userId = String(comment.user.id);

    if (userId === rules.ciId && /^代码有更新,重置PR验证状态$/.test(comment.body)) {

      break;

    }

    if (administrators.has(userId) && /^approve api check$/.test(comment.body)) {

      ApiCheckResult.formatCheckResult = true;

      scanResult = ['api_check: true'];

      break;

    }

  }

  return scanResult;

}

exports.reqGitApi = reqGitApi;