/**
 *  @module     Electricity
 *  @overview   Defines the `Electricity` class
 * 
 *  @author     Animesh Mishra <hello@animesh.ltd>
 *  @copyright  © 2018 Animesh Ltd. All Rights Reserved.
 */

import * as Request         from "request-promise-native"
import * as UtilityError    from "./UtilityError"
import { Provider }         from "./Provider"
import { RIPCreds }         from "./RIPCreds"
import { UtilityBill }      from "../index"
import { StatusResponse }   from "./StatusResponse"

/** Manages electricity bill payments. */
export class Electricity {
    public provider: Provider
    public accountNumber: string
    public amount: number = 0

    public constructor(provider: Provider, accountNumber: string) {
        this.provider = provider
        this.accountNumber = accountNumber
    }

    /**
     *  Returns the current due amount of the account. Since utility APIs,
     *  expect exact bill amount you must call this API before calling the payment API.
     * 
     *  In case of MSEDC - MAHARASHTRA provider, you must send `billUnit` and `processingCycle` information
     *  too through the optional `extra` parameter.
     *  
     *  In case of Reliance Energy - MUMBAI provider, you must send `cycleNumber` information through the 
     *  optional `extra` parameter.
     * 
     *  In case of Torrent Power provider, you must send `city` name through the `extra` parameter.
     *  
     *  @param creds    Merchant credentials to connect to Rocket in Pocket API 
     *  @param extra    Optional parameters only required for some parameters
     */
    public async Validate(creds: RIPCreds, extra?: any): Promise<number> {
        let options = {
            method: "GET",
            uri: `https://${creds.baseURL}/validate/electricity`,
            headers: {
                Accept: "application/json"
            },
            qs: {
                client_id: creds.merchantID,
                client_key: creds.merchantKey,
                provider_code: this.provider.code,
                connection_provider: this.provider.name,
                account_number: this.accountNumber,
                amount: this.amount,
                bill_unit: extra ? extra.billUnit : null,
                processing_cycle: extra ? extra.processingCycle : null,
                cycle_number: extra ? extra.cycleNumber : null,
                city: extra ? extra.city : null
            }
        }

        let response = await Request(options)
        response = JSON.parse(response)
        let error = UtilityError.Check(response)
        if (error) { throw error }

        return Number(response.particulars.due_amount)
    }

    /**
     *  Makes the bill payment of electricity connection.
     * 
     *  In case of MSEDC - MAHARASHTRA provider, you must send `billUnit` and `processingCycle` information
     *  too through the optional `extra` parameter.
     *  
     *  In case of Reliance Energy - MUMBAI provider, you must send `cycleNumber` information through the 
     *  optional `extra` parameter.
     * 
     *  In case of Torrent Power provider, you must send `city` name through the `extra` parameter.
     * 
     *  @param creds    Merchant credentials to access Rocket in Pocket API
     *  @param amount   In Rupees. Must be exact due amount.
     *  @param extra    Any optional parameters.
     */
    public async Pay(creds: RIPCreds, amount: number, live: boolean = false, extra?: any): Promise<UtilityBill> {
        let options = {
            method: "GET",
            uri: `https://${creds.baseURL}/pay/electricity`,
            headers: {
                Accept: "application/json"
            },
            qs: {
                client_id: creds.merchantID,
                client_key: creds.merchantKey,
                provider_code: this.provider.code,
                connection_provider: this.provider.name,
                account_number: this.accountNumber,
                amount: amount,
                bill_unit: extra ? extra.billUnit : null,
                processing_cycle: extra ? extra.processingCycle : null,
                cycle_number: extra ? extra.cycleNumber : null,
                city: extra ? extra.city : null,
                live: live
            }
        }

        let response = await Request(options)
        response = JSON.parse(response)
        let error = UtilityError.Check(response)
        if(error) { throw error }

        return new UtilityBill(this, response)
    }

    /**
     *  Returns a list of all electricity providers supported by Rocket in Pocket
     *  API.
     */
    public static async GetProviders(creds: RIPCreds): Promise<Array<Provider>> {
        let options = {
            method: "GET",
            uri: `https://${creds.baseURL}/providers/electricity`,
            headers: {
                Accept: "application/json"
            },
            qs: {
                client_id: creds.merchantID,
                client_key: creds.merchantKey
            }
        }

        let response = await Request(options)
        response = JSON.parse(response)
        let error = UtilityError.Check(response)
        if(error) { throw error }

        let providers = Provider.InitList(response)
        return providers
    }

    /**
     *  Checks status of a previously submitted bill payment request. We make use of Rocket in
     *  Pocket callbacks for status updates. So this is largely implemented as a backup in
     *  case RIP callback systems fail.
     *
     *  @param transactionID    Magic Batua transaction ID of the recharge request
     */
    public static async CheckStatus(creds: RIPCreds, transactionID: string): Promise<StatusResponse> {
        let options = {
            method: "GET",
            uri: `https://${creds.baseURL}/recharge/order`,
            headers: {
                Accept: "application/json"
            },
            qs: {
                client_order_id: transactionID
            }
        }

        let response = await Request(options)
        response = JSON.parse(response)
        let error = UtilityError.Check(response)
        if(error) { throw error }

        return {
            operatorReference: response.opr_transid,
            vendorReference: response.rocket_trans_id,
            status: response.status,
            date: response.datetime
        }
    }
}