import request from 'superagent'
import JiraService from './jira-service.js'

export default class ZephyrService {

    constructor( config ) {
        this.request = request;
        this.config = config;
        this.jira = new JiraService(config);
    }

    getDate() {
        const date = new Date();

        let dateStr = (date.getDate());
        dateStr += '/';
        dateStr += date.getMonth()+1;
        dateStr += '/';
        dateStr += date.getFullYear().toString().substring(2, 4);

        return dateStr;
    };

    getDateAndTime() {
        const date = new Date();

        let dateStr = (date.getDate());
        dateStr += '/';
        dateStr += date.getMonth()+1;
        dateStr += '/';
        dateStr += date.getFullYear().toString().substring(2, 4);
        dateStr += ' ';
        dateStr += date.getHours();
        dateStr += ':';
        dateStr += ( '0'  + date.getMinutes()).substr(-2);

        return dateStr;
    };

    async getCycles(version) {
        let versionId;
        if (isNaN(version)) {
            try {
                versionId = await this.jira.getVersionId(version, false);
                if (!versionId) {
                    throw new Error("Version does not exist");
                }
            } catch (error) {
                console.error('Could not retrieve versionId, error: ' + error);
            }
        } else {
            versionId = version
        }

        if (!this.projectId) {
            try {
                this.projectId = await this.jira.getProjectId();
            } catch (error) {
                console.error('Could not retrieve projectId, error: ' + error);
                return null;
            }
        }

        try {
            let response = await this.request
            .get(this.config.baseUrl + this.config.zapiUrl + '/cycle?projectId=' + this.projectId + '&versionId=' + versionId)
            .auth(this.config.username, this.config.password);
            let result = {};
            if ( response.body){
                (Object.keys(response.body)).forEach(key => {
                    let keyNum = Number(key);
                    if (!isNaN(keyNum) && keyNum > 0) {
                        result[keyNum] = response.body[key]
                    }
                });
            }
            return result;
        } catch (error) {
            console.error('Unable to get zephyr cycles for version ' + version + ', error: ' + error);
            return null;
        }
    }

    async deleteCycle(cycleId) {
        try {
            let response = await this.request
            .delete(this.config.baseUrl + this.config.zapiUrl + '/cycle/' + cycleId)
            .auth(this.config.username, this.config.password);
            if ( response.body.jobProgressToken ){
                let finished = false;
                while (!finished){
                    await new Promise( resolve => setTimeout(resolve, 500) );
                    let progressResponse = await this.request
                    .get(this.config.baseUrl + this.config.zapiUrl + '/execution/jobProgress/' + response.body.jobProgressToken + '?type=cycle_delete_job_progress' )
                    .auth(this.config.username, this.config.password);
                    if ( progressResponse.body ){
                        if (progressResponse.body.errorMessage && !progressResponse.body.errorMessage===""){
                            console.error("Zephyr-service deleteCycle, error from progress while deleting cycleId: " + cycleId + " MESSAGE: " + progressResponse.body.errorMessage );
                            finished = true;
                        } else if (progressResponse.body.progress >= 1 ){
                            console.log("Zephyr-service deleteCycle, finished deleting cycle with Id: " + cycleId );
                            finished = true;
                        } else {
                            // console.log("Zephyr-service deleteCycle, processing delete of cycle with Id: " + cycleId + ' PROGRESS: ' + progressResponse.body.progress);
                            await new Promise( resolve => setTimeout(resolve, 500) );
                        }
                    } else {
                        console.error("Zephyr-service deleteCycle, couldn't retrieve progresss while deleting cycleId: " + cycleId);
                        finished = true;
                    }
                }
            } else {
                console.error("Zephyr-service deleteCycle, No jobProgressToken received while deleting cycleId: " + cycleId);
            }
        } catch (error) {
            console.error('Unable to delete zephyr cycle, error: ' + error);
            return null;
        }
    }

    async createCycle(version, cyclename, environment, startDate, endDate) {
        let activeSprintId, versionId, projectId;
        try {
            activeSprintId = await this.jira.getActiveSprintId();
        } catch (error) {
            console.error('Could not retrieve activeSprintId');
        }
        try {
            versionId = await this.jira.getVersionId(version);
        } catch (error) {
            console.error('Could not retrieve versionId');
        }
        try {
            projectId = await this.jira.getProjectId();
        } catch (error) {
            console.error('Could not retrieve versionId');
            return null;
        }
        let body = {
            name: cyclename,
            startDate: startDate,//this.getDate(),
            endDate: endDate,//this.getDate(),
            environment: environment,
            projectId: projectId,
            versionId: versionId || '-1',
            sprintId: activeSprintId || '-1'
        };
        try {
            let response = await this.request
            .post(this.config.baseUrl + this.config.zapiUrl + '/cycle')
            .auth(this.config.username, this.config.password)
            .type('json')
            .send(body);
            this.cycleId = response.body.id;
            this.projectId = projectId;
			this.versionId = versionId;
            return this.cycle_info;
        } catch (error) {
            console.error('Unable to create zephyr cycle, error: ' + error);
            return null;
        }
    }

    async createExecution(issueKey) {
        let issueId;
        if (!this.cycleId) {
            console.error('No cycle defined, run createCycle before');
            return null;
        }
        try {
            issueId = await this.jira.getIssueId(issueKey);
        } catch (error) {
            console.error('Unable to get jira Issue id, error: ' + error);
            return null;
        }
        let cycleId = this.cycleId;
        let projectId = this.projectId;
        try {
            let response = await this.request
            .post(this.config.baseUrl + this.config.zapiUrl + '/execution')
            .auth(this.config.username, this.config.password)
            .type('json')
            .send({
                cycleId,
                issueId,
                projectId
            });
            // return execution id
            return Object.keys(response.body)[0];
        } catch (error) {
            console.error('Unable create zephyr execution, error: ' + error);
            return null;
        }
    }

    async getExecutionStepId(executionId, stepId) {
        stepId = String(stepId);
        try {
            let response = await this.request
            .get( this.config.baseUrl + this.config.zapiUrl + '/stepResult?executionId=' + executionId)
            .auth(this.config.username, this.config.password);
            let steps = response.body || [];
            const index = steps.findIndex((step) => String(step.stepId) === stepId);
            if (index === -1) {
                console.log(`StepId: ${stepId} not found`);
            } else {
                return  response.body[index].id;
            }
        } catch (error) {
            console.error('Unable to get zephyr stepId, error: ' + error);
            return null;
        }
    }

    async updateExecutionTestStep(stepId, status, comment) {
        try {
            let response = await this.request
            .put(this.config.baseUrl + this.config.zapiUrl + '/stepResult/' + stepId)
            .auth(this.config.username, this.config.password)
            .type('json')
            .send({
                'status': status,
                'comment': comment
            });
            return response.body;
        } catch (error) {
            console.error('Unable update zephyr testStep execution, error: ' + error);
            return null;
        }
    }

    async updateExecution(executionId, status, comment) {
        try {
            let response = await this.request
            .put(this.config.baseUrl + this.config.zapiUrl + '/execution/' + executionId + '/execute')
            .auth(this.config.username, this.config.password)
            .type('json')
            .send({
                'status': status,
                'comment': comment
            });
            return response.body;
        } catch (error) {
            console.error('Unable update zephyr execution, error: ' + error);
            return null;
        }
    }

    async addStepAttachment(stepId, filePath) {
        try {
            let response = await this.request
            .post(this.config.baseUrl + this.config.zapiUrl + '/attachment?entityId=' + stepId + '&entityType=STEPRESULT')
            .auth(this.config.username, this.config.password)
            .set("X-Atlassian-Token", "nocheck")
            .accept('application/json')
            .attach('file', filePath);
            return response.body;
        } catch (error) {
            console.error('Unable upload attachment to zephyr execution teststep, error: ' + error);
            return null;
        }
    }

    async addExecutionAttachment(executionId, filePath) {
        try {
            let response = await this.request
            .post(this.config.baseUrl + this.config.zapiUrl + '/attachment?entityId=' + executionId + '&entityType=EXECUTION')
            .auth(this.config.username, this.config.password)
            .set("X-Atlassian-Token", "nocheck")
            .accept('application/json')
            .attach('file', filePath);
            return response.body;
        } catch (error) {
            console.error('Unable upload attachment to zephyr execution, error: ' + error);
            return null;
        }
    }
}

