package com.example.fuzzControll.service.impl;

import com.alibaba.fastjson2.JSON;
import com.example.fuzzControll.annotion.NeedCutAfter;
import com.example.fuzzControll.annotion.NeedCutAround;
import com.example.fuzzControll.annotion.NeedCutBefore;
import com.example.fuzzControll.conf.KittyProperties;
import com.example.fuzzControll.constents.MutationConstent;
import com.example.fuzzControll.domain.bo.FuzzParams;
import com.example.fuzzControll.exception.testException.AflnetException;
import com.example.fuzzControll.exception.testException.CmdException;
import com.example.fuzzControll.exception.testException.FuzzException;
import com.example.fuzzControll.domain.bo.TestEntity;
import com.example.fuzzControll.service.FuzzParamsService;
import com.example.fuzzControll.service.MutationService;
import com.example.fuzzControll.tools.system.GlobalClass;
import com.example.fuzzControll.tools.test.TestCmdTools;
import com.example.fuzzControll.tools.test.TestTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Service("mutationService")
@Slf4j
class MutationServiceImpl implements MutationService {
    TestCmdTools cmdTools = new TestCmdTools();
    @Autowired
    KittyProperties kitty;
    @Autowired
    FuzzParamsService fuzzParamsService;

    @Override
    @NeedCutAround(name ="kitty",function = "generation")
    public Map<String, List<String>> generation(TestEntity testEntity) throws FuzzException, CmdException {
        /*存入参数*/
        int missionId = GlobalClass.missionInfoMapper.selectTopMissionId();
        boolean flag = fuzzParamsService.saveFuzzParams(new FuzzParams(JSON.toJSONString(testEntity.getParamJson()), new Date(), missionId));
        if (!flag) {
            throw new AflnetException("Save params error!");
        }
        String cmd = parseParameters(testEntity);
        if (cmd.isEmpty()) {
            throw new FuzzException("cmd is null ! The number of parameters does not match!");
        }
        return cmdTools.runProgramCmdAndResult(cmd, "mutation", "Mutation-" + testEntity.getTestClassName());
    }

    public String parseParameters(TestEntity testEntity) {
        try {
            switch (testEntity.getTestClassName().toLowerCase()) {
                case "bit":
                    return variationGranularityCmd(testEntity, 1);
                case "byte":
                    return variationGranularityCmd(testEntity, 2);
                case "sqlinjection":
                    return distortionLibCmd(testEntity, 2);
                case "commandinjection":
                    return distortionLibCmd(testEntity, 1);
                case "outofbuffer":
                    return distortionLibCmd(testEntity, 3);
                case "directorytraversal":
                    return distortionLibCmd(testEntity, 4);
                case "8-bitinteger":
                    return distortionLibCmd(testEntity, 5);
                case "16-bitinteger":
                    return distortionLibCmd(testEntity, 6);
                case "32-bitinteger":
                    return distortionLibCmd(testEntity, 7);
                case "bitflip":
                    return mutationStrategyCmd(testEntity, 8);
                case "twobitflip":
                    return mutationStrategyCmd(testEntity, 9);
                case "fourbitflip":
                    return mutationStrategyCmd(testEntity, 10);
                case "byteflip":
                    return mutationStrategyCmd(testEntity, 11);
                case "wordflip":
                    return mutationStrategyCmd(testEntity, 12);
                case "dwordflip":
                    return mutationStrategyCmd(testEntity, 13);
                case "blockremove":
                    return mutationStrategyCmd(testEntity, 14);
                case "blockduplicate":
                    return mutationStrategyCmd(testEntity, 15);
                case "blockset":
                    return mutationStrategyCmd(testEntity, 16);
                case "bitflips":
                    return mutationStrategyCmd(testEntity, 17);
                case "byteflips":
                    return mutationStrategyCmd(testEntity, 1);
                case "interestint8muta":
                    return mutationStrategyCmd(testEntity, 2);
                case "interestint16muta":
                    return mutationStrategyCmd(testEntity, 3);
                case "interestint32muta":
                    return mutationStrategyCmd(testEntity, 4);
                case "onebyterndom":
                    return mutationStrategyCmd(testEntity, 5);
                case "mutibytesrandom":
                    return mutationStrategyCmd(testEntity, 6);
                case "deleteonebyterandom":
                    return mutationStrategyCmd(testEntity, 7);
                case "deletemutibytesrandom":
                    return mutationStrategyCmd(testEntity, 8);
                case "shufflebytesrandom":
                    return mutationStrategyCmd(testEntity, 9);
                case "swapadjointwobytes":
                    return mutationStrategyCmd(testEntity, 10);
                default:
                    throw new FuzzException("Unknown method!");
            }
        } catch (FuzzException e) {
            throw new FuzzException("Count of params is not match or unknown protocol!");
        }
    }

    private String distortionLibCmd(TestEntity testEntity, int methodNum) {
        if (!TestTools.paramsLenghtTest(testEntity.getParamJson().length, 2, "distortionLib" + methodNum))
            return "";
        String dst_ip = null;
        String dst_port = null;
        try {
            dst_ip = testEntity.getParamJson()[0];
            dst_port = testEntity.getParamJson()[1];
        } catch (Exception e) {
            log.error("distortionLib [{}] 参数解析失败!", methodNum);
        }
        return kitty.getVenvPath() + " " + kitty.getMutationPath() + MutationConstent.TEST_MUTATED_LIBS + " -g " + methodNum + " -d " + dst_ip + " -p " + dst_port;
    }


    private String variationGranularityCmd(TestEntity testEntity, int methodNum) throws FuzzException {
        if (!TestTools.paramsLenghtTest(testEntity.getParamJson().length, 2, "variationGranularity" + methodNum))
            return "";
        String dst_ip = null;
        String dst_port = null;
        try {
            dst_ip = testEntity.getParamJson()[0];
            dst_port = testEntity.getParamJson()[1];
        } catch (Exception e) {
            throw new FuzzException("Parameter parsing failed !");
        }
        return kitty.getVenvPath() + " " + kitty.getMutationPath() + MutationConstent.TEST_GRANULARITY_BIT_BYTE + " -g " + methodNum + " -d " + dst_ip + " -p " + dst_port;
    }

    private String mutationStrategyCmd(TestEntity testEntity, int methodNum) {
        if (!TestTools.paramsLenghtTest(testEntity.getParamJson().length, 2, "mutationStrategy" + methodNum))
            return "";
        String dst_ip = null;
        String dst_port = null;
        try {
            dst_ip = testEntity.getParamJson()[0];
            dst_port = testEntity.getParamJson()[1];
        } catch (Exception e) {
            log.error("mutationStrategy [{}] 参数解析失败!", methodNum);
        }
        return kitty.getVenvPath() + " " + kitty.getMutationPath() + MutationConstent.TEST_MUTATION_STRATEGY + " -g " + methodNum + " -d " + dst_ip + " -p " + dst_port;
    }

}