import axios from 'axios';

const xml2JSON = require('xml2json-light');
const json2XML = require('json2xml');

import { PSAccount, PSItemDetails, PSCheckoutDetails } from './pagseguro.model';

export default class PagSeguro {

    dadosConta: PSAccount = { email: '', token: '' };
    itens: PSItemDetails[] = [];
    api;

    urlPagSeguro: string = '';
    currency: string = '';
    reference: string = '';
    redirectURL: string = '';
    notificationURL: string = '';

    constructor(dados: PSAccount){
        this.dadosConta = dados;
        if(dados.sandbox) {
            this.urlPagSeguro       = 'https://ws.sandbox.pagseguro.uol.com.br';
        } else {
            this.urlPagSeguro       = 'https://ws.pagseguro.uol.com.br';
        }
        this.currency               = 'BRL';
        this.itens                  = [];
        this.api = axios.create({
            baseURL: this.urlPagSeguro,
            headers: {
                'Content-Type': 'application/xml; charset=UTF-8'
            }
        });
    }

    /**
     * Moeda da transação
     * @param cur 
     */
    setCurrency(cur: string) {
        this.currency = cur;
    }

    /**
     * Adiciona um item a lista de itens do pagamento
     * @param item 
     */
    addItem(item: PSItemDetails) {
        item.amount = Number(item.amount).toFixed(2);
        this.itens.push(item);
    }

    /**
     * Define a lista de itens do pagamento.
     * @param itens 
     */
    setItens(itens: PSItemDetails[]) {
        this.itens = itens;
    }

    /**
     * Define a referência do pagamento
     * @param referencia 
     */
    setReference(referencia: string) {
        this.reference = referencia;
    }

    /**
     * Define a URL de Retorno
     * @param redirectURL 
     */
    setRedirectURL(redirectURL: string) {
        this.redirectURL = redirectURL;
    }

    /**
     * Define a URL de notificação de status do pagamento.
     * @param notificationURL 
     */
    setNotificationURL(notificationURL: string) {
        this.notificationURL = notificationURL;
    }

    /**
     * Valida se os atributos obrigatórios para pagamento foram informados.
     */
    validPayment(){
        if(!this.notificationURL) {
            throw new Error('[TrowDev/PagSeguro-SDK] notificationURL is required.');
        } else if(!this.redirectURL) {
            throw new Error('[TrowDev/PagSeguro-SDK] redirectURL is required.');
        } else if(!this.reference) {
            throw new Error('[TrowDev/PagSeguro-SDK] reference is required.');
        } else if(!this.itens || this.itens.length === 0) {
            throw new Error('[TrowDev/PagSeguro-SDK] itens is required.');
        } else if(!this.currency) {
            throw new Error('[TrowDev/PagSeguro-SDK] currency is required.');
        }
        return true;
    }

    buildPayment(){
        const data: any = {};
        if(this.validPayment()) {
            data.items = [];
            this.itens.forEach(item => {
                data['items'].push({ item });
            });
            data['notificationURL']             = this.notificationURL;
            data['redirectURL']                 = this.redirectURL;
            data['reference']                   = this.reference;
            data['currency']                    = this.currency;
        }
        let ret = json2XML({ checkout: data });
        ret = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + ret;
        return ret;
    }

    /**
     * Envia a requisição ao PagSeguro para gerar um código de pagamento.
     */
    async payment(): Promise<PSCheckoutDetails> {
        const dataPayment               = this.buildPayment();
        const { email, token }          = this.dadosConta;
        const endpoint                  = `/v2/checkout?email=${email}&token=${token}`;
        const resp:any                  = await this.api.post(endpoint, dataPayment).then(ret => {
            return ret;
        }).catch(err => {
            console.log(err);
        });
        if(!resp || resp.status != 200) {
            console.log('[@trowdev/PagSeguro-SDK] Status Response: '+resp.status);
            throw new Error('[@trowdev/PagSeguro-SDK] Invalid Response.');
        }
        return xml2JSON.xml2json(resp.data);
    }

    /**
     * Busca os detalhes de uma transação pelo código da transação.
     * @param idTransacao 
     */
    async transactionStatus(idTransacao: string) {
        const { email, token }  = this.dadosConta;
        const endpoint          = `/v3/transactions/${idTransacao}?email=${email}&token=${token}`;
        const resp: any         = await this.api.get(endpoint).then(ret => {
            return ret;
        }).catch(err => {
            console.log(err);
        });
        if(!resp) {
            throw new Error('[@trowdev/PagSeguro-SDK] Invalid Response.');
        }
        return xml2JSON.xml2json(resp.data);
    }

    /**
     * Busca os detalhes de uma transação pelo código da notificação IPN.
     * @param ipnCodigoTransacao 
     */
    async notificationStatus(ipnCodigoTransacao: string) {
        const { email, token }  = this.dadosConta;
        const endpoint          = `/v3/transactions/notifications/${ipnCodigoTransacao}?email=${email}&token=${token}`;
        const resp: any         = await this.api.get(endpoint).then(ret => {
            return ret;
        }).catch(err => {
            console.log(err);
        });
        if(!resp) {
            throw new Error('[@trowdev/PagSeguro-SDK] Invalid Response.');
        }
        return xml2JSON.xml2json(resp.data);
    }

}