/* eslint-disable camelcase */

import binding from './binding'
import { C } from './constants'
import { Lot } from './lot'
import { Chat } from './chat'
import { WebxdcInfo } from './context'
const debug = require('debug')('deltachat:node:message')

export enum MessageDownloadState {
  Available = C.DC_DOWNLOAD_AVAILABLE,
  Done = C.DC_DOWNLOAD_DONE,
  Failure = C.DC_DOWNLOAD_FAILURE,
  InProgress = C.DC_DOWNLOAD_IN_PROGRESS,
}

/**
 * Helper class for message states so you can do e.g.
 *
 * if (msg.getState().isPending()) { .. }
 *
 */
export class MessageState {
  constructor(public state: number) {
    debug(`MessageState constructor ${state}`)
  }

  isUndefined() {
    return this.state === C.DC_STATE_UNDEFINED
  }

  isFresh() {
    return this.state === C.DC_STATE_IN_FRESH
  }

  isNoticed() {
    return this.state === C.DC_STATE_IN_NOTICED
  }

  isSeen() {
    return this.state === C.DC_STATE_IN_SEEN
  }

  isPending() {
    return this.state === C.DC_STATE_OUT_PENDING
  }

  isFailed() {
    return this.state === C.DC_STATE_OUT_FAILED
  }

  isDelivered() {
    return this.state === C.DC_STATE_OUT_DELIVERED
  }

  isReceived() {
    return this.state === C.DC_STATE_OUT_MDN_RCVD
  }
}

/**
 * Helper class for message types so you can do e.g.
 *
 * if (msg.getViewType().isVideo()) { .. }
 *
 */
export class MessageViewType {
  constructor(public viewType: number) {
    debug(`MessageViewType constructor ${viewType}`)
  }

  isText() {
    return this.viewType === C.DC_MSG_TEXT
  }

  isImage() {
    return this.viewType === C.DC_MSG_IMAGE || this.viewType === C.DC_MSG_GIF
  }

  isGif() {
    return this.viewType === C.DC_MSG_GIF
  }

  isAudio() {
    return this.viewType === C.DC_MSG_AUDIO || this.viewType === C.DC_MSG_VOICE
  }

  isVoice() {
    return this.viewType === C.DC_MSG_VOICE
  }

  isVideo() {
    return this.viewType === C.DC_MSG_VIDEO
  }

  isFile() {
    return this.viewType === C.DC_MSG_FILE
  }

  isVideochatInvitation() {
    return this.viewType === C.DC_MSG_VIDEOCHAT_INVITATION
  }
}

interface NativeMessage {}
/**
 * Wrapper around dc_msg_t*
 */
export class Message {
  constructor(public dc_msg: NativeMessage) {
    debug('Message constructor')
    if (dc_msg === null) {
      throw new Error('dc_msg can not be null')
    }
  }

  toJson() {
    debug('toJson')
    const quotedMessage = this.getQuotedMessage()
    const viewType = binding.dcn_msg_get_viewtype(this.dc_msg)
    return {
      chatId: this.getChatId(),
      webxdcInfo: viewType == C.DC_MSG_WEBXDC ? this.webxdcInfo : null,
      downloadState: this.downloadState,
      duration: this.getDuration(),
      file: this.getFile(),
      fromId: this.getFromId(),
      id: this.getId(),
      quotedText: this.getQuotedText(),
      quotedMessageId: quotedMessage ? quotedMessage.getId() : null,
      receivedTimestamp: this.getReceivedTimestamp(),
      sortTimestamp: this.getSortTimestamp(),
      text: this.getText(),
      timestamp: this.getTimestamp(),
      hasLocation: this.hasLocation(),
      hasHTML: this.hasHTML,
      viewType,
      state: binding.dcn_msg_get_state(this.dc_msg),
      hasDeviatingTimestamp: this.hasDeviatingTimestamp(),
      showPadlock: this.getShowpadlock(),
      summary: this.getSummary().toJson(),
      subject: this.subject,
      isSetupmessage: this.isSetupmessage(),
      isInfo: this.isInfo(),
      isForwarded: this.isForwarded(),
      dimensions: {
        height: this.getHeight(),
        width: this.getWidth(),
      },
      videochatType: this.getVideochatType(),
      videochatUrl: this.getVideochatUrl(),
      overrideSenderName: this.overrideSenderName,
      parentId: this.parent?.getId(),
    }
  }

  getChatId(): number {
    return binding.dcn_msg_get_chat_id(this.dc_msg)
  }

  get webxdcInfo(): WebxdcInfo | null {
    let info = binding.dcn_msg_get_webxdc_info(this.dc_msg)
    return info
      ? JSON.parse(binding.dcn_msg_get_webxdc_info(this.dc_msg))
      : null
  }

  get downloadState(): MessageDownloadState {
    return binding.dcn_msg_get_download_state(this.dc_msg)
  }

  get parent(): Message | null {
    let msg = binding.dcn_msg_get_parent(this.dc_msg)
    return msg ? new Message(msg) : null
  }

  getDuration(): number {
    return binding.dcn_msg_get_duration(this.dc_msg)
  }

  getFile(): string {
    return binding.dcn_msg_get_file(this.dc_msg)
  }

  getFilebytes(): number {
    return binding.dcn_msg_get_filebytes(this.dc_msg)
  }

  getFilemime(): string {
    return binding.dcn_msg_get_filemime(this.dc_msg)
  }

  getFilename(): string {
    return binding.dcn_msg_get_filename(this.dc_msg)
  }

  getFromId(): number {
    return binding.dcn_msg_get_from_id(this.dc_msg)
  }

  getHeight(): number {
    return binding.dcn_msg_get_height(this.dc_msg)
  }

  getId(): number {
    return binding.dcn_msg_get_id(this.dc_msg)
  }

  getQuotedText(): string {
    return binding.dcn_msg_get_quoted_text(this.dc_msg)
  }

  getQuotedMessage(): Message | null {
    const dc_msg = binding.dcn_msg_get_quoted_msg(this.dc_msg)
    return dc_msg ? new Message(dc_msg) : null
  }

  getReceivedTimestamp(): number {
    return binding.dcn_msg_get_received_timestamp(this.dc_msg)
  }

  getSetupcodebegin() {
    return binding.dcn_msg_get_setupcodebegin(this.dc_msg)
  }

  getShowpadlock() {
    return Boolean(binding.dcn_msg_get_showpadlock(this.dc_msg))
  }

  getSortTimestamp(): number {
    return binding.dcn_msg_get_sort_timestamp(this.dc_msg)
  }

  getState() {
    return new MessageState(binding.dcn_msg_get_state(this.dc_msg))
  }

  getSummary(chat?: Chat) {
    const dc_chat = (chat && chat.dc_chat) || null
    return new Lot(binding.dcn_msg_get_summary(this.dc_msg, dc_chat))
  }

  get subject(): string {
    return binding.dcn_msg_get_subject(this.dc_msg)
  }

  getSummarytext(approxCharacters: number): string {
    approxCharacters = approxCharacters || 0
    return binding.dcn_msg_get_summarytext(this.dc_msg, approxCharacters)
  }

  getText(): string {
    return binding.dcn_msg_get_text(this.dc_msg)
  }

  getTimestamp(): number {
    return binding.dcn_msg_get_timestamp(this.dc_msg)
  }

  getViewType() {
    return new MessageViewType(binding.dcn_msg_get_viewtype(this.dc_msg))
  }

  getVideochatType(): number {
    return binding.dcn_msg_get_videochat_type(this.dc_msg)
  }

  getVideochatUrl(): string {
    return binding.dcn_msg_get_videochat_url(this.dc_msg)
  }

  getWidth(): number {
    return binding.dcn_msg_get_width(this.dc_msg)
  }

  get overrideSenderName(): string {
    return binding.dcn_msg_get_override_sender_name(this.dc_msg)
  }

  hasDeviatingTimestamp() {
    return binding.dcn_msg_has_deviating_timestamp(this.dc_msg)
  }

  hasLocation() {
    return Boolean(binding.dcn_msg_has_location(this.dc_msg))
  }

  get hasHTML() {
    return Boolean(binding.dcn_msg_has_html(this.dc_msg))
  }

  isDeadDrop() {
    // TODO: Fix
    //return this.getChatId() === C.DC_CHAT_ID_DEADDROP
    return false
  }

  isForwarded() {
    return Boolean(binding.dcn_msg_is_forwarded(this.dc_msg))
  }

  isIncreation() {
    return Boolean(binding.dcn_msg_is_increation(this.dc_msg))
  }

  isInfo() {
    return Boolean(binding.dcn_msg_is_info(this.dc_msg))
  }

  isSent() {
    return Boolean(binding.dcn_msg_is_sent(this.dc_msg))
  }

  isSetupmessage() {
    return Boolean(binding.dcn_msg_is_setupmessage(this.dc_msg))
  }

  latefilingMediasize(width: number, height: number, duration: number) {
    binding.dcn_msg_latefiling_mediasize(this.dc_msg, width, height, duration)
  }

  setDimension(width: number, height: number) {
    binding.dcn_msg_set_dimension(this.dc_msg, width, height)
    return this
  }

  setDuration(duration: number) {
    binding.dcn_msg_set_duration(this.dc_msg, duration)
    return this
  }

  setFile(file: string, mime?: string) {
    if (typeof file !== 'string') throw new Error('Missing filename')
    binding.dcn_msg_set_file(this.dc_msg, file, mime || '')
    return this
  }

  setLocation(longitude: number, latitude: number) {
    binding.dcn_msg_set_location(this.dc_msg, longitude, latitude)
    return this
  }

  setQuote(quotedMessage: Message | null) {
    binding.dcn_msg_set_quote(this.dc_msg, quotedMessage?.dc_msg)
    return this
  }

  setText(text: string) {
    binding.dcn_msg_set_text(this.dc_msg, text)
    return this
  }

  setHTML(html: string) {
    binding.dcn_msg_set_html(this.dc_msg, html)
    return this
  }

  setOverrideSenderName(senderName: string) {
    binding.dcn_msg_set_override_sender_name(this.dc_msg, senderName)
    return this
  }

  /** Force the message to be sent in plain text.
   *
   * This API is for bots, there is no need to expose it in the UI.
   */
  forcePlaintext() {
    binding.dcn_msg_force_plaintext(this.dc_msg)
  }
}
