import superagent from 'super-agent'

export default class ConfluenceService {

    constructor( config ) {
        this.request = superagent;
        this.config = config;
        this.config.apiPath = '/rest/api';
        this.config.extension = ''; // no extension by default
    }

    async getContentById(pageId) {
        try {
            let response = await this.request
            .get(this.config.baseUrl + this.config.apiPath + "/content/" + pageId + this.config.extension + "?expand=body.storage,version")
            .auth(this.config.username, this.config.password);
            return response.body;
        } catch (error) {
            console.error('Unable to retrieve confluence content by page id, error: ' + error);
            return null;
        }

    }

    async updatePage(pageId, pageContent) {
        let currentContent = await this.getContentById(pageId);

        let page = {
            "id": pageId,
            "type": "page",
            "title": currentContent.title,
            "space": {
                "key": this.config.confluenceProject
            },
            "version": {
                "number": currentContent.version.number + 1,
                "minorEdit": false
            },
            "body": {
                "storage": {
                    "value": pageContent,
                    "representation": "storage"
                }
            }
        };
        try {
            let response = await this.request
            .put(this.config.baseUrl + this.config.apiPath + "/content/" + pageId + this.config.extension + "?expand=body.storage,version")
            .auth(this.config.username, this.config.password)
            .type('json')
            .send(page)
            return response;
        } catch (error) {
            console.error('Unable to update confluence page content, error: ' + error);
            return null;
        }
    }

    async getAttachments(pageId) {
        let query =
        "?spaceKey=" + this.config.confluenceProject +
        "&expand=version,container";
        let retry = 3;

        while (retry > 0) {
            try {
                let response = await this.request
                .get(this.config.baseUrl + this.config.apiPath + "/content/" + pageId + "/child/attachment" + query )
                .auth(this.config.username, this.config.password);
                if (response.body.results) {
                    return response.body.results;
                } else {
                    throw new Error('response.body on request cnfl getAttachments did not contain results');
                }
            } catch (error) {
                if ( retry == 1 ) {
                    throw error;
                } else {
                    console.error('Unable to retrieve confluence attachments by page id, error: ' + error);
                }
            }
            // wait 5000 ms
            await new Promise( resolve => setTimeout(resolve, 5000) );
            retry -= 1;
        }
        return null;
    }

    async getAttachmentText (cnflAtt) {
        if (!cnflAtt.cnflObject){
            let attachments = await this.getAttachments(attachment.pageId);
            if (attachments) {
                let attIndex = attachments.findIndex((attachment) => attachment.title.toLowerCase() === cnflAtt.filename.toLowerCase());
                if (attIndex !== -1) {
                    cnflAtt.cnflObject = attachments[attIndex];
                }
            }
        }

        if (cnflAtt.cnflObject && cnflAtt.cnflObject['_links']['download']) {
            let retry = 3;
            while (retry > 0) {
                try {
                    let response = await this.request
                    .get(this.config.baseUrl + cnflAtt.cnflObject['_links']['download'])
                    .auth(this.config.username, this.config.password)
                    .buffer(true)
                    .parse(this.request.parse['application/json']);
                    if (response['text']) {
                        return response['text'];
                    } else {
                        throw new Error('response on request cnfl getAttachmentText did not contain text');
                    }
                } catch (error) {
                    console.error('Unable to retrieve confluence attachment text, error: ' + error);
                }
                // wait 5000 ms
                await new Promise( resolve => setTimeout(resolve, 5000) );
                retry -= 1;
            }
        }
        return null;
    }

    async createAttachment(cnflAtt) {
        try {
            let response = await this.request
            .post(this.config.baseUrl + this.config.apiPath + "/content/" + cnflAtt.pageId + "/child/attachment")
            .auth(this.config.username, this.config.password)
            .set("X-Atlassian-Token", "nocheck")
            .attach("file", cnflAtt.localFilepath );
            if (response.body){
                cnflAtt.cnflObject = response.body;
            }
            return response;
        } catch (error) {
            console.error('Unable to create confluence attachment, error: ' + error);
            return null;
        }

    }

    async updateAttachment (cnflAtt) {
        try {
            let response = await this.request
            .post(this.config.baseUrl + this.config.apiPath + "/content/" + cnflAtt.pageId + "/child/attachment/" + cnflAtt.cnflObject.id + "/data")
            .auth(this.config.username, this.config.password)
            .set("X-Atlassian-Token", "nocheck")
            .attach("file", cnflAtt.localFilepath );
            if (response.body){
                cnflAtt.cnflObject = response.body;
            }
            return response;
        } catch (error) {
            console.error('Unable to update confluence attachment, error: ' + error);
            return null;
        }
    }

    async createOrUpdateAttachment (cnflAtt) {
        if (!cnflAtt.cnflObject){
            let attachments = await this.getAttachments(cnflAtt.pageId);
            if (attachments) {
                let attIndex = attachments.findIndex((attachment) => attachment.title.toLowerCase() === cnflAtt.filename.toLowerCase());
                if (attIndex !== -1) {
                    cnflAtt.cnflObject = attachments[attIndex];
                }
            }
        }
        if (!cnflAtt.cnflObject) {
            // Attachment doesn't exist yet, Create
            return await this.createAttachment(cnflAtt);
        } else {
            // Attachment exists, Update
            return await this.updateAttachment(cnflAtt);
        }
    }

    async deleteAndCreateNewAttachment (cnflAtt) {
        if (!cnflAtt.cnflObject){
            let attachments = await this.getAttachments(cnflAtt.pageId);
            if (attachments) {
                let attIndex = attachments.findIndex((attachment) => attachment.title.toLowerCase() === cnflAtt.filename.toLowerCase());
                if (attIndex !== -1) {
                    cnflAtt.cnflObject = attachments[attIndex];
                }
            }
        }
        if (cnflAtt.cnflObject) {
            // await this.deleteAttachment(cnflAtt);
          await this.deleteAttachment(cnflAtt);
        }
        return await this.createAttachment(cnflAtt);
    }

    async deleteAttachment(cnflAtt) {
        try {
            let response = await this.request
            .del(this.config.baseUrl + this.config.apiPath + "/content/" + cnflAtt.cnflObject.id)
            .auth(this.config.username, this.config.password);
            if (response.ok){
                cnflAtt.cnflObject = null;
            }
            return response;
        } catch (error) {
            console.error('Unable to delete confluence attachment, error: ' + error);
            return null;
        }
    }
}
