package cz.moneta.test.dsl.hypos.tasks;

import cz.moneta.test.dsl.hypos.enums.DocumentState;
import cz.moneta.test.dsl.hypos.enums.DocumentTemplate;
import cz.moneta.test.dsl.hypos.enums.HyposContractState;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.hypos.hyposdb.HyposDbEndpoint;

import static cz.moneta.test.dsl.hypos.enums.HyposContractState.*;

import org.jooq.Record;
import org.jooq.Result;
import org.junit.jupiter.api.Assertions;

import java.util.HashMap;
import java.util.Map;

public class HyposDbTasks {
    private final StoreAccessor harness;
    private static final String EMPTY_RESULT = "";

    private final String GET_CONTRACT_ID_QUERY =
            "SELECT contract.ctr_code AS CONTRACTID " +
                    "FROM dbo.calc calc JOIN dbo.contract contract ON contract.ctr_id = calc.contact " +
                    "WHERE calc.id = _HYPOKALKULACKAID_";

    private final String GET_CONTRACT_STATE_QUERY =
            "SELECT ctr_fk_state AS STATE " +
                    "FROM dbo.contract " +
                    "WHERE ctr_code = _CONTRACTID_";

    private final String GET_APPROVAL_REQUEST_STATE_QUERY =
            "SELECT approval_request.state AS STATE " +
                    "FROM dbo.approval_request approval_request " +
                    "JOIN dbo.contract contract ON contract.ctr_id = approval_request.contract " +
                    "WHERE contract.ctr_code = _CONTRACTID_ " +
                    "AND approval_request.type = 'scoring'";

    private final String GET_CONTRACT_BY_STATE_QUERY =
            "SELECT TOP 1 ctr_code AS CONTRACTID " +
                    "FROM dbo.contract " +
                    "WHERE ctr_fk_state = '_CONTRACTSTATE_' " +
                    "AND ctr_fk_process = 7 " +
                    "ORDER BY ctr_code DESC";

    private final String GET_CONTRACT_WITH_BU_BY_STATE_QUERY =
            "SELECT TOP 1 c.ctr_code AS CONTRACTID " +
                    "FROM dbo.contract c " +
                    "JOIN dbo.contract_detail cd ON cd.ctd_fk_contract = c.ctr_id " +
                    "WHERE c.ctr_fk_state = '_CONTRACTSTATE_' " +
                    "AND c.ctr_fk_process = 7 " +
                    "AND cd.current_account_id != 102920 " +
                    "ORDER BY c.ctr_code DESC";

    private final String GET_CLIENT_DETAIL_BY_PIN_QUERY =
            "SELECT contract.ctr_code AS CTR_CODE, " +
                    "person.cif AS CIF, " +
                    "person.first_name AS FIRST_NAME, " +
                    "person.last_name AS LAST_NAME, " +
                    "person.pin AS PIN " +
                    "FROM dbo.contract contract " +
                    "JOIN dbo.client client ON contract.ctr_id = client.contract " +
                    "JOIN dbo.person person ON client.person = person.id " +
                    "WHERE pin = '_PIN_'";

    private final String GET_DOCUMENT_STATE_QUERY =
            "SELECT TOP 1 d.doc_fk_status AS STATE " +
                    "FROM dbo.docs d " +
                    "JOIN dbo.contract c ON c.ctr_id = d.doc_fk_contract " +
                    "WHERE c.ctr_code = _CONTRACTID_ " +
                    "and d.doc_fk_template = _TEMPLATE_ " +
                    "AND d.doc_valid = 1 " +
                    "AND d.doc_fk_status = 1 " +
                    "AND d.doc_created > DATEADD(MINUTE, -10, SYSDATETIME()) " +
                    "ORDER BY d.doc_created DESC";

    String HYPOS_CONTRACT_ID = "HYPOS_CONTRACT_ID";

    public HyposDbTasks(StoreAccessor harness) {
        this.harness = harness;
    }

    private String getContractState(String contractId) {
        return harness.getEndpoint(HyposDbEndpoint.class)
                .executeSql(GET_CONTRACT_STATE_QUERY.replace("_CONTRACTID_", contractId))
                .getValues("STATE")
                .get(0)
                .toString();
    }

    private String getApprovalRequestState(String contractId) {
        return harness.getEndpoint(HyposDbEndpoint.class)
                .executeSql(GET_APPROVAL_REQUEST_STATE_QUERY.replace("_CONTRACTID_", contractId))
                .getValues("STATE")
                .get(0)
                .toString();
    }

    private String getDocumentState(String contractId, DocumentTemplate template) {
        Result<Record> records = harness.getEndpoint(HyposDbEndpoint.class)
                .executeSql(GET_DOCUMENT_STATE_QUERY.replace("_CONTRACTID_", contractId).replace("_TEMPLATE_", template.getValue()));
        if (records.isEmpty()) {
            return EMPTY_RESULT;
        } else {
            return records.getValues("STATE").get(0).toString();
        }
    }

    public String getContractId(String hypokalkulackaId) {
        String contractId = harness.getEndpoint(HyposDbEndpoint.class)
                .executeSql(GET_CONTRACT_ID_QUERY.replace("_HYPOKALKULACKAID_", hypokalkulackaId))
                .getValues("CONTRACTID")
                .get(0)
                .toString();
        harness.store(contractId, HYPOS_CONTRACT_ID);
        return contractId;
    }

    public String getContractIdByState(HyposContractState contractState) {
        return harness.getEndpoint(HyposDbEndpoint.class)
                .executeSql(GET_CONTRACT_BY_STATE_QUERY.replace("_CONTRACTSTATE_", contractState.getValue()))
                .getValues("CONTRACTID")
                .get(0)
                .toString();
    }

    public String getContractIdWithBuByState(HyposContractState contractState) {
        return harness.getEndpoint(HyposDbEndpoint.class)
                .executeSql(GET_CONTRACT_WITH_BU_BY_STATE_QUERY.replace("_CONTRACTSTATE_", contractState.getValue()))
                .getValues("CONTRACTID")
                .get(0)
                .toString();
    }

    public Map<String, String> getClientDetailsByPin(String clientPin) {
        Map<String, String> personDetails = new HashMap<>();
        Result<Record> records = harness.getEndpoint(HyposDbEndpoint.class)
                .executeSql(GET_CLIENT_DETAIL_BY_PIN_QUERY.replace("_PIN_", clientPin));

        if (records.isEmpty()) {
            Assertions.fail("No results found from the initial SQL query. Was the input PIN correct? Are you using the correct environment?");
        }
        personDetails.put("CTR_CODE", records.get(0).getValue("CTR_CODE", String.class));
        personDetails.put("CIF", records.get(0).getValue("CIF", String.class));
        personDetails.put("FIRST_NAME", records.get(0).getValue("FIRST_NAME", String.class));
        personDetails.put("LAST_NAME", records.get(0).getValue("LAST_NAME", String.class));
        personDetails.put("FULL_NAME", String.format("%s %s", records.get(0).getValue("FIRST_NAME", String.class), records.get(0).getValue("LAST_NAME", String.class)));
        personDetails.put("PIN", clientPin);
        return personDetails;
    }

    public Boolean contractPrescoringFinished(String contractId) {
        //1 SQL query each 5 seconds for 180 seconds
        for (int i = 0; i < 36; i++) {
            try {
                Thread.sleep(5000);
                String currentState = getContractState(contractId);
                harness.log("Current prescoring status for contract {} is {}", contractId, currentState);
                if (currentState.equals(OBCHOD_ZALOZEN_KONTROLA_OK.getValue())) {
                    return true;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public Boolean contractScoringFinished(String contractId) {
        //1 SQL query each 5 seconds for 180 seconds
        for (int i = 0; i < 36; i++) {
            try {
                Thread.sleep(5000);
                String currentState = getContractState(contractId);
                harness.log("Current scoring status for contract {} is {}", contractId, currentState);
                if (currentState.equals(OVEROVANI.getValue())) {
                    return true;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public Boolean contractScoringWithApVerificationFinished(String contractId) {
        //1 SQL query each 5 seconds for 180 seconds
        for (int i = 0; i < 36; i++) {
            try {
                Thread.sleep(5000);
                String currentState = getApprovalRequestState(contractId);
                harness.log("Current approval request status for contract {} is {}", contractId, currentState);
                if (currentState.equals(DOPLN_DOKLADY.getValue())) {
                    return true;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public Boolean loanAccountOpeningFinished(String contractId) {
        //1 SQL query each 10 seconds for 420 seconds
        for (int i = 0; i < 42; i++) {
            try {
                Thread.sleep(10000);
                String currentState = getContractState(contractId);
                harness.log("Current create loan status for contract {} is {}", contractId, currentState);
                if (currentState.equals(PRIPRAVA_SMLUV.getValue())) {
                    return true;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public Boolean contractDocumentFinished(String contractId, DocumentTemplate template) {
        //1 SQL query each 10 seconds for 120 seconds
        for (int i = 0; i < 12; i++) {
            try {
                Thread.sleep(10000);
                String currentState = getDocumentState(contractId, template);
                harness.log("Current document {} status for contract {} is {}", template, contractId, DocumentState.getNameByValue(currentState));
                if (currentState.equals(DocumentState.GENERATED.getValue())) {
                    return true;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}