{"size": 3640, "ext": "js", "max_stars_repo_path": "src/transporters/Smsc.js", "max_stars_repo_name": "borodayev/sms-sender", "max_stars_repo_stars_event_min_datetime": "2018-03-31T12:16:36.000Z", "max_stars_repo_stars_event_max_datetime": "2019-10-24T00:31:45.000Z", "max_issues_repo_path": "src/transporters/Smsc.js", "max_issues_repo_name": "FrankAst/smsc-js", "max_issues_repo_issues_event_min_datetime": "2018-03-31T10:10:35.000Z", "max_issues_repo_issues_event_max_datetime": "2020-03-06T19:53:30.000Z", "max_forks_repo_path": "src/transporters/Smsc.js", "max_forks_repo_name": "FrankAst/smsc-js", "max_forks_repo_forks_event_min_datetime": "2018-04-12T09:53:01.000Z", "max_forks_repo_forks_event_max_datetime": "2018-10-23T04:42:39.000Z"}
{"max_stars_count": 5, "max_issues_count": 36, "max_forks_count": 4, "avg_line_length": 24.5945945946, "max_line_length": 93, "alphanum_fraction": 0.6057692308}
// @flow

import 'isomorphic-fetch';
import { URLSearchParams } from 'url';

import type {
  SendSmsResponseT,
  GetCostResponseT,
  GetStatusResponseT,
  GetBalanceResponseT,
  SmsStatusT,
  ProviderI,
} from '../definitions';

type CredentialsT = {|
  login: string,
  password: string,
|};

export default class Smsc implements ProviderI {
  credentials: CredentialsT;
  commonSmsParams = {
    tinyurl: 1,
    charset: 'utf-8',
    translit: 1,
  };

  constructor(credentials: CredentialsT) {
    this.credentials = credentials;
  }

  // make request to SMSC API
  async _send(cmd: 'send' | 'status' | 'balance', params: Object): Promise<Object> {
    const { login, password } = this.credentials || {};
    const extendedParams = {
      login,
      psw: password,
      ...params,
      fmt: 3, // return response in JSON format
    };
    const paramsUrl = new URLSearchParams(extendedParams);
    const url = `http://smsc.ru/sys/${cmd}.php?${paramsUrl.toString()}`;
    const res = await fetch(url);
    return res.json();
  }

  // get more detailed description on https://smsc.kz/api/http/status_messages/statuses/#menu
  // eslint-disable-next-line class-methods-use-this
  _prepareStatus(status: number): SmsStatusT {
    switch (status) {
      case -3:
        return 'error'; // -3 - Message not found
      case -1:
        return 'pending'; // -1 - Waiting for sending
      case 0:
        return 'pending'; // 0 - Given to operator
      case 1:
        return 'ok'; // 1 - Delivered
      case 2:
        return 'ok'; // 2 - Read
      case 3:
        return 'error'; // 3 - Overdue message
      case 20:
        return 'error'; // 20 - Can not deliver
      case 22:
        return 'error'; // 22 - Wrong number
      case 23:
        return 'error'; // 23 - Prohibited
      case 24:
        return 'error'; // 24 - Insufficient funds
      case 25:
        return 'error'; // 24 - Inaccessible number
      default:
        return 'error';
    }
  }

  // send message
  async sendSms(phone: string, message: string): Promise<SendSmsResponseT> {
    const params = {
      phones: phone,
      mes: message,
      ...this.commonSmsParams,
    };
    const rawResponse = await this._send('send', params);
    const res = {
      messageId: `${rawResponse.id}-${phone}`,
      rawResponse,
    };
    return res;
  }

  // get cost of message without sending
  async getCost(phone: string, message: string): Promise<GetCostResponseT> {
    const params = {
      cost: 1,
      phones: phone,
      mes: message,
      ...this.commonSmsParams,
    };

    const rawResponse = await this._send('send', params);
    const res = {
      cost: rawResponse.cost,
      rawResponse,
    };
    return res;
  }

  // get status of message (messageId format: id-phoneNumber)
  async getStatus(messageId: string): Promise<GetStatusResponseT> {
    const params = {
      id: messageId.split('-')[0],
      phone: messageId.split('-')[1],
      all: 2,
      ...this.commonSmsParams,
    };

    const rawResponse = await this._send('status', params);
    const res = {
      status: this._prepareStatus(rawResponse.status),
      rawResponse,
    };
    return res;
  }

  // get current balance
  async getBalance(): Promise<GetBalanceResponseT> {
    const params = {
      cur: 1,
      ...this.commonSmsParams,
    };

    const rawResponse = await this._send('balance', params);
    const res = {
      balance: rawResponse.balance,
      rawResponse,
    };
    return res;
  }

  // get current provider name
  // eslint-disable-next-line class-methods-use-this
  getProviderName(): string {
    return 'smsc';
  }
}
