exports.createServer = null
exports.connect =
exports.isIP =
exports.isIPv4 =
exports.isIPv6 =
  function () { return true };

const { NSocketClient, ConnData } = require("../../socket.js")

function concatTypedArrays(a, b) { // a, b TypedArray of same type
  let c = new Uint8Array(a.byteLength + b.byteLength);
  c.set(a, 0);
  c.set(b, a.byteLength);
  return c;
}

let decoder = new TextDecoder()
let encoder = new TextEncoder()

const EventEmitter = require('events')
class NodeClient extends EventEmitter {
  constructor(nclient) {
    super();
    this.control = {}
    this.cacheBuffer = new Uint8Array()
    this.connect(nclient)
  }

  async connect(nclient) {
    let c = await nclient.connection(this.control, (msg) => {
      this.cacheBuffer = concatTypedArrays(this.cacheBuffer, msg)
      this.emit("ready")
      this.emit("readable")
      this.emit("data", msg)
    })

    if (c.code != 0) {
      throw msg
    } else {
      this.handleCloseEvents()
      this.emit("connect")
    }
  }

  handleCloseEvents() {
    this.control.promise
      .then((msg)=> {
        if (msg.code != 0) {
          this.emit("error", msg)
        } else {
          this.emit("end", msg)
          this.emit("close", msg)
        }
      })
      .catch((msg) => {
        this.emit("error", msg)
      })
      .finally(() => {
        this.control.end()
      })
  }

  write(str) {
    let req = new ConnData()
    if (str instanceof Uint8Array) {
      if (str.constructor != Uint8Array) {
        req.setData(new Uint8Array(str))
      } else {
        req.setData(str)
      }
    } else {
      req.setData(encoder.encode(str))
    }
    this.control.write(req)
    return this
  }

  read(len) {
    if (len > this.cacheBuffer.length) {
      // FXIME: how to normal handle this ?
      console.warn(`net.Socket: You try read ${len} bytes but there only have ${this.cacheBuffer.length} bytes`)
      return null
    }
    let res = this.cacheBuffer.slice(0, len)
    this.cacheBuffer = this.cacheBuffer.slice(len)
    return Buffer.from(res)
  }

  setNoDelay() {
    // FIXME: remove this
    return true
  }

  end() {
    this.control.end()
  }
}

exports.createConnection = function(opts, callback) {
  if (typeof opts === 'string') {
    opts = {
      "path": opts
    }
  }
  if (!opts) opts = {
    host: "localhost"
  }

  let family
  let address
  if (opts.path) {
    family = "unix"
    address = opts.path
  } else if (opts.port && opts.host) {
    family = "tcp"
    address = `${opts.host}:${opts.port}`
  } else {
    throw `Only support the unix and tcp socket! Please the options.path or options.host and options.port field.`
  }
  return new NodeClient(new NSocketClient(family, address))
}
