import { IApiService } from './Api';
import { IAuthService } from './Auth';
import { IConfig } from './Config';
import Promise from 'bluebird';
import { IStorageService } from './Storage';

export interface IBilling {
  setCustomerId(id: string): void;
  self(): any;
  getCard(): any;
  createCard(data: any): any;
  getCustomerInfo(): any;
  updateCustomerInfo(data: any): any;
  createCustomer(data: any): any;
  getCustomerSubscription(): any;
  deleteCustomerSubscription(data: any): any;
  getInvoices(): any;
  getUpcomingInvoices(): any;
  downloadInvoiceUrl(invoiceId: string): any;
  getPlan(): any;
  getUsage(): any;
}

class Billing implements IBilling {
  public customerInfo: any = {
    id: '',
    description: '',
    email: ''
  };
  public cardInfo: any = {
    number: '',
    cvc: '',
    exp_month: '',
    exp_year: ''
  };
  public customerCard: any;
  public invoices: any;
  public upcomingInvoices: any;
  public planInfo: any;

  constructor(private config: IConfig, private api: IApiService, private storage: IStorageService) {
    return;
  }

  public setCustomerId(id: string): void {
    this.customerInfo.id = id;
  }

  public self(): any {
    return this.fetch(`${this.config.billing_url}/self`);
  }

  public getCard(): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/cards`)
        .then((res: any) => {
          if (res.data && res.data.length) {
            this.customerCard = res.data[0];
            resolve(this.customerCard);
            return;
          }
          resolve(false);
        })
        .catch(reject);
    });
    return p;
  }

  public createCard(data: any): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/cards`, 'POST', data)
        .then(res => {
          if (res) {
            this.customerCard = res;
            resolve(this.customerCard);
            return;
          }
          resolve(false);
          return;
        })
        .catch(reject);
    });
    return p;
  }

  public getCustomerInfo(): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      return this.fetch(`${this.config.billing_url}/customers`)
        .then(res => {
          if (res && !res.deleted) {
            this.customerInfo = res;
            resolve(this.customerInfo);
            return;
          }
          resolve(false);
        })
        .catch(reject);
    });
    return p;
  }

  public updateCustomerInfo(data: any): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/customers`, 'PUT', {
        email: data.email,
        description: data.description,
        metadata: data.metadata
      })
        .then(res => {
          if (res) {
            resolve(res);
          } else {
            resolve(false);
          }
        })
        .catch(reject);
    });
    return p;
  }

  public createCustomer(data: any): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/customers`, 'POST', data)
        .then(res => {
          this.customerInfo = res;
          resolve(this.customerInfo);
        })
        .catch(reject);
    });
    return p;
  }

  public getCustomerSubscription(): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/customers/subscription`)
        .then(res => {
          resolve(res);
        })
        .catch(reject);
    });
    return p;
  }

  public deleteCustomerSubscription(data: any): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/customers/subscription`, 'DELETE', data)
        .then(res => {
          resolve(res);
        })
        .catch(reject);
    });
    return p;
  }

  public getInvoices(): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/invoices`)
        .then(res => {
          if (res.data && res.data.length) {
            this.invoices = res.data;
            resolve(this.invoices);
            return;
          }
          resolve(false);
        })
        .catch(reject);
    });
    return p;
  }

  public getInvoice(id: string): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/invoices/${id}`)
        .then(res => {
          resolve(res);
        })
        .catch(reject);
    });
    return p;
  }

  public getUpcomingInvoices(): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/invoices/upcoming`)
        .then(res => {
          console.log('getUpcomingInvoices', res);
          if (res.lines && res.lines.data.length) {
            this.upcomingInvoices = res;
            resolve(this.upcomingInvoices);
            return;
          }
          resolve(false);
        })
        .catch((err)=>{
          if (err.statusCode === 404) {
            resolve(false);
          } else {
            reject(err);
          }
        });
    });
    return p;
  }

  public downloadInvoiceUrl(invoiceId: string): any {
    return `${this.config.billing_url}/invoices/download/${invoiceId}`;
  }

  public getPlan(): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/plans`)
        .then(res => {
          if (!res.deleted) {
            this.planInfo = res;
            resolve(this.planInfo);
            return;
          }
          resolve(false);
        })
        .catch((err)=>{
          if (err.statusCode === 404) {
            resolve(false);
          } else {
            reject(err);
          }
        });
    });
    return p;
  }

  public getUsage(): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/usage`)
        .then(res => {
          resolve(res.data);
        })
        .catch(reject);
    });
    return p;
  }

  public createIntent(data: any): any {
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.fetch(`${this.config.billing_url}/intents/${data.type}`, 'POST')
        .then(res => {
          resolve(res);
        })
        .catch(reject);
    });
    return p;
  }  

  private fetch(url: string, method: string = 'GET', body?: any, buffer?: boolean): Promise<any> {
    let data: any = {
      method,
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${this.api.tokens.access_token}`
      }
    };
    let token: string = '';
    if (this.storage) {
      token = this.storage.persistent.get('access_token');
    }
    if (!token && this.api.tokens && this.api.tokens.access_token) {
      token = this.api.tokens.access_token;
    }

    if (token) {
      data.headers.Authorization = `Bearer ${token}`;
    }
    if (body) {
      data.body = JSON.stringify(body);
    }
    let error: number = 0;
    let p: Promise<any> = new Promise((resolve, reject) => {
      fetch(url, data)
        .then(response => {
          if (response.status >= 300) {
            error = response.status;
            if (response.status >= 500) {
              reject(response);
              return;
            }
          }
          return buffer ? response.arrayBuffer() : response.json();
        })
        .then(response => {
          if (error) {
            reject(response);
          } else {
            resolve(response);
          }
        })
        .catch(err => {
          reject(err);
        });
    });
    return p;
  }
}

export default Billing;
