package inji.api.testscripts;

import inji.utils.InjiWalletConfigManager;
import inji.utils.InjiWalletUtil;
import io.mosip.testrig.apirig.dto.OutputValidationDto;
import io.mosip.testrig.apirig.dto.TestCaseDTO;
import io.mosip.testrig.apirig.testrunner.HealthChecker;
import io.mosip.testrig.apirig.testrunner.JsonPrecondtion;
import io.mosip.testrig.apirig.utils.*;
import io.restassured.response.Response;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.testng.*;
import org.testng.annotations.*;
import org.testng.internal.BaseTestMethod;
import org.testng.internal.TestResult;

import javax.ws.rs.core.MediaType;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

public class AddIdentity extends InjiWalletUtil implements ITest {
    private static final Logger logger = Logger.getLogger(AddIdentity.class);
    protected String testCaseName = "";
    public Response response = null;

    @Override
    public String getTestName() {
        return testCaseName;

    }

    @BeforeClass
    public static void setLogLevel() {
        if (InjiWalletConfigManager.IsDebugEnabled())
            logger.setLevel(Level.ALL);
        else
            logger.setLevel(Level.ERROR);
    }

    /**
     * Data provider class provides test case list
     *
     * @return object of data provider
     */
    @DataProvider(name = "testcaselist")
    public Object[] getTestCaseList(ITestContext context) {
        String ymlFile = context.getCurrentXmlTest().getLocalParameters().get("ymlFile");
        logger.info("Started executing yml: " + ymlFile);
        return getYmlTestData(ymlFile);
    }

    /**
     * Test method for OTP Generation execution
     *
     * @throws AuthenticationTestException
     * @throws AdminTestException
     */
    @Test(dataProvider = "testcaselist")
    public void test(TestCaseDTO testCaseDTO) throws Exception {
        testCaseName = testCaseDTO.getTestCaseName();
        if (HealthChecker.signalTerminateExecution) {
            throw new SkipException(
                    GlobalConstants.TARGET_ENV_HEALTH_CHECK_FAILED + HealthChecker.healthCheckFailureMapS);
        }

        if (testCaseDTO.getEndPoint().contains("mock-identity-system")) {
            String individualIDStr = String.valueOf(Calendar.getInstance().getTimeInMillis());
            String phoneStr = "+91" + generateRandomNumberString(10);
            String emailStr = testCaseName + "@mosip.net";
            String passWordStr = properties.getProperty("passwordForAddIdentity");
            String url = ApplnURI.replace("-internal", "") + testCaseDTO.getEndPoint();

            String inputJson = getJsonFromTemplate(testCaseDTO.getInput(), testCaseDTO.getInputTemplate());

            inputJson = InjiWalletUtil.inputstringKeyWordHandeler(inputJson, testCaseName);

            if (inputJson.contains("$RANDOMINDIVIDUALIDFORMOCKIDENTITY$")) {
                inputJson = replaceKeywordWithValue(inputJson, "$RANDOMINDIVIDUALIDFORMOCKIDENTITY$", individualIDStr);
                writeAutoGeneratedId(testCaseName, "UIN", individualIDStr);
            }

            if (inputJson.contains("$EMAILIDFORMOCKIDENTITY$")) {
                inputJson = replaceKeywordWithValue(inputJson, "$EMAILIDFORMOCKIDENTITY$", emailStr);
                writeAutoGeneratedId(testCaseName, "EMAIL", emailStr);
            }
            if (inputJson.contains("$PASSWORDFORMOCKIDENTITY$")) {
                inputJson = replaceKeywordWithValue(inputJson, "$PASSWORDFORMOCKIDENTITY$", passWordStr);
                writeAutoGeneratedId(testCaseName, "PASSWORD", passWordStr);
            }
            if (inputJson.contains("$PHONEFORMOCKIDENTITY$")) {
                inputJson = replaceKeywordWithValue(inputJson, "$PHONEFORMOCKIDENTITY$", phoneStr);
                writeAutoGeneratedId(testCaseName, "PHONE", phoneStr);
            }

            GlobalMethods.reportRequest(null, inputJson, url);

            response = RestClient.post(url, inputJson);

            GlobalMethods.reportResponse(response.getHeaders().asList().toString(), url, response);
        } else {

            testCaseDTO.setInputTemplate(AdminTestUtil.modifySchemaGenerateHbs(testCaseDTO.isRegenerateHbs()));
            String uin = JsonPrecondtion
                    .getValueFromJson(
                            RestClient.getRequestWithCookie(ApplnURI + "/v1/idgenerator/uin", MediaType.APPLICATION_JSON,
                                    MediaType.APPLICATION_JSON, COOKIENAME,
                                    new KernelAuthentication().getTokenByRole(testCaseDTO.getRole())).asString(),
                            "response.uin");


            testCaseDTO = InjiWalletUtil.isTestCaseValidForTheExecution(testCaseDTO);

            DateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
            Calendar cal = Calendar.getInstance();
            String timestampValue = dateFormatter.format(cal.getTime());
            String genRid = "27847" + generateRandomNumberString(10) + timestampValue;

            String jsonInput = testCaseDTO.getInput();

            String inputJson = getJsonFromTemplate(jsonInput, testCaseDTO.getInputTemplate(), false);

            inputJson = inputJson.replace("$UIN$", uin);
            inputJson = inputJson.replace("$RID$", genRid);
            String phoneNumber = "";
            String email = testCaseName + "@mosip.net";
            if (inputJson.contains("$PHONENUMBERFORIDENTITY$")) {
                if (!phoneSchemaRegex.isEmpty())
                    try {
                        phoneNumber = genStringAsperRegex(phoneSchemaRegex);
                    } catch (Exception e) {
                        logger.error(e.getMessage());
                    }
                inputJson = replaceKeywordWithValue(inputJson, "$PHONENUMBERFORIDENTITY$", phoneNumber);
                inputJson = replaceKeywordWithValue(inputJson, "$EMAILVALUE$", email);
            }
            inputJson = InjiWalletUtil.inputstringKeyWordHandeler(inputJson, testCaseName);

            response = postWithBodyAndCookie(ApplnURI + testCaseDTO.getEndPoint(), inputJson, COOKIENAME,
                    testCaseDTO.getRole(), testCaseDTO.getTestCaseName());

            Map<String, List<OutputValidationDto>> ouputValid = OutputValidationUtil.doJsonOutputValidation(
                    response.asString(), getJsonFromTemplate(testCaseDTO.getOutput(), testCaseDTO.getOutputTemplate()),
                    testCaseDTO, response.getStatusCode());
            Reporter.log(ReportUtil.getOutputValidationReport(ouputValid));

            if (!OutputValidationUtil.publishOutputResult(ouputValid))
                throw new AdminTestException("Failed at output validation");
            if (testCaseDTO.getTestCaseName().contains("_Pos")) {
                writeAutoGeneratedId(testCaseDTO.getTestCaseName(), "UIN", uin);
                writeAutoGeneratedId(testCaseDTO.getTestCaseName(), "RID", genRid);
                writeAutoGeneratedId(testCaseDTO.getTestCaseName(), "EMAIL", testCaseDTO.getTestCaseName() + "@mosip.net");
                writeAutoGeneratedId(testCaseDTO.getTestCaseName(), "PHONE", phoneNumber);
            }
            if (!phoneNumber.isEmpty())
                writeAutoGeneratedId(testCaseDTO.getTestCaseName(), "PHONE", phoneNumber);
        }
    }

    /**
     * The method ser current test name to result
     *
     * @param result
     */
    @AfterMethod(alwaysRun = true)
    public void setResultTestName(ITestResult result) {
        try {
            Field method = TestResult.class.getDeclaredField("m_method");
            method.setAccessible(true);
            method.set(result, result.getMethod().clone());
            BaseTestMethod baseTestMethod = (BaseTestMethod) result.getMethod();
            Field f = baseTestMethod.getClass().getSuperclass().getDeclaredField("m_methodName");
            f.setAccessible(true);
            f.set(baseTestMethod, testCaseName);
        } catch (Exception e) {
            Reporter.log("Exception : " + e.getMessage());
        }
    }

    @AfterClass(alwaysRun = true)
    public void waittime() {

        try {
            logger.info(
                    "waiting for " + properties.getProperty("Delaytime") + " mili secs after UIN Generation In IDREPO");
            Thread.sleep(Long.parseLong(properties.getProperty("Delaytime")));

        } catch (Exception e) {
            logger.error("Exception : " + e.getMessage());
            Thread.currentThread().interrupt();
        }

    }
}
