import { AsciiSession } from '../../../transport/ascii'
import { MsgView } from '../../../buffer'
import { MsgType } from '../../../types/enum'
import { IJsFixLogger, IJsFixConfig } from '../../../config'
// interfaces generated by compiler to make messages easy in an IDE
import { ITradeCaptureReportRequest, ITradeCaptureReport, MsgTag, SessionRejectReason, SubscriptionRequestType, TradeRequestStatus } from '../../../types/FIX4.4/repo'
import { TradeFactory } from './trade-factory'

export class TradeCaptureServer extends AsciiSession {
  private readonly logger: IJsFixLogger
  private readonly fixLog: IJsFixLogger
  private readonly tradeFactory: TradeFactory = new TradeFactory()
  private timerHandle: NodeJS.Timer = null

  constructor (public readonly config: IJsFixConfig) {
    super(config)
    this.logReceivedMsgs = true
    this.logger = config.logFactory.logger(`${this.me}:TradeCaptureServer`)
    this.fixLog = config.logFactory.plain(`jsfix.${config.description.application.name}.txt`)
  }

  protected onApplicationMsg (msgType: string, view: MsgView): void {
    this.logger.info(`${view.toJson()}`)
    switch (msgType) {
      case MsgType.TradeCaptureReportRequest: {
        this.tradeCaptureReportRequest(view.toObject())
        break
      }

      default: {
        const seqNum = view.getTyped(MsgTag.MsgSeqNum)
        this.send(msgType, this.config.factory.reject(msgType, seqNum, `${this.me}: unexpected msg type '${msgType}'`, SessionRejectReason.InvalidMsgType))
        break
      }
    }
  }

  protected onReady (view: MsgView): void {
    // server waits for client to make a request
    this.logger.info('ready for requests.')
  }

  protected onStopped (): void {
    this.logger.info('stopped')
    if (this.timerHandle) {
      clearInterval(this.timerHandle)
    }
  }

  protected onLogon (view: MsgView, user: string, password: string): boolean {
    return true
  }

  // use msgType for example to persist only trade capture messages to database
  protected onDecoded (msgType: string, txt: string): void {
    this.fixLog.info(txt)
  }

  // no delimiter substitution on transmit messages
  protected onEncoded (msgType: string, txt: string): void {
    this.fixLog.info(AsciiSession.asPiped(txt))
  }

  private tradeCaptureReportRequest (tcr: ITradeCaptureReportRequest): void {
    this.logger.info(`received tcr ${tcr.TradeRequestID}`)
    // send back an ack.
    this.send(MsgType.TradeCaptureReportRequestAck, TradeFactory.tradeCaptureReportRequestAck(tcr, TradeRequestStatus.Accepted))
    // send some trades
    const batch: ITradeCaptureReport[] = this.tradeFactory.batchOfTradeCaptureReport()
    batch.forEach((tc: ITradeCaptureReport) => {
      this.send(MsgType.TradeCaptureReport, tc)
    })
    this.send(MsgType.TradeCaptureReportRequestAck, TradeFactory.tradeCaptureReportRequestAck(tcr, TradeRequestStatus.Completed))
    // start sending the odd 'live' trade
    switch (tcr.SubscriptionRequestType) {
      case SubscriptionRequestType.SnapshotAndUpdates: {
        this.timerHandle = setInterval(() => {
          if (Math.random() < 0.4) {
            const tc: ITradeCaptureReport = this.tradeFactory.singleTradeCaptureReport()
            this.send(MsgType.TradeCaptureReport, tc)
          }
        }, 5000)
        break
      }
    }
  }
}
