import {
  fromByteWidth,
  fwidth,
  iwidth,
  paddingSize,
  toByteWidth,
  uwidth,
} from './bit-width-util.js';
import {BitWidth} from './bit-width.js';
import {toUTF8Array} from './flexbuffers-util.js';
import {StackValue} from './stack-value.js';
import {
  isNumber,
  isTypedVectorElement,
  toTypedVector,
} from './value-type-util.js';
import {ValueType} from './value-type.js';

interface StackPointer {
  stackPosition: number;
  isVector: boolean;
  presorted?: boolean;
}

export class Builder {
  buffer: ArrayBuffer;
  view: DataView;

  readonly stack: Array<StackValue> = [];
  readonly stackPointers: Array<StackPointer> = [];
  offset = 0;
  finished = false;
  readonly stringLookup: Record<string, StackValue> = {};
  readonly keyLookup: Record<string, StackValue> = {};
  readonly keyVectorLookup: Record<string, StackValue> = {};
  readonly indirectIntLookup: Record<number, StackValue> = {};
  readonly indirectUIntLookup: Record<number, StackValue> = {};
  readonly indirectFloatLookup: Record<number, StackValue> = {};

  constructor(
    size = 2048,
    private dedupStrings = true,
    private dedupKeys = true,
    private dedupKeyVectors = true,
  ) {
    this.buffer = new ArrayBuffer(size > 0 ? size : 2048);
    this.view = new DataView(this.buffer);
  }

  private align(width: BitWidth) {
    const byteWidth = toByteWidth(width);
    this.offset += paddingSize(this.offset, byteWidth);
    return byteWidth;
  }

  computeOffset(newValueSize: number): number {
    const targetOffset = this.offset + newValueSize;
    let size = this.buffer.byteLength;
    const prevSize = size;
    while (size < targetOffset) {
      size <<= 1;
    }
    if (prevSize < size) {
      const prevBuffer = this.buffer;
      this.buffer = new ArrayBuffer(size);
      this.view = new DataView(this.buffer);
      new Uint8Array(this.buffer).set(new Uint8Array(prevBuffer), 0);
    }
    return targetOffset;
  }

  pushInt(value: number, width: BitWidth): void {
    if (width === BitWidth.WIDTH8) {
      this.view.setInt8(this.offset, value);
    } else if (width === BitWidth.WIDTH16) {
      this.view.setInt16(this.offset, value, true);
    } else if (width === BitWidth.WIDTH32) {
      this.view.setInt32(this.offset, value, true);
    } else if (width === BitWidth.WIDTH64) {
      this.view.setBigInt64(this.offset, BigInt(value), true);
    } else {
      throw `Unexpected width: ${width} for value: ${value}`;
    }
  }

  pushUInt(value: number, width: BitWidth): void {
    if (width === BitWidth.WIDTH8) {
      this.view.setUint8(this.offset, value);
    } else if (width === BitWidth.WIDTH16) {
      this.view.setUint16(this.offset, value, true);
    } else if (width === BitWidth.WIDTH32) {
      this.view.setUint32(this.offset, value, true);
    } else if (width === BitWidth.WIDTH64) {
      this.view.setBigUint64(this.offset, BigInt(value), true);
    } else {
      throw `Unexpected width: ${width} for value: ${value}`;
    }
  }

  private writeInt(value: number, byteWidth: number) {
    const newOffset = this.computeOffset(byteWidth);
    this.pushInt(value, fromByteWidth(byteWidth));
    this.offset = newOffset;
  }

  private writeUInt(value: number, byteWidth: number) {
    const newOffset = this.computeOffset(byteWidth);
    this.pushUInt(value, fromByteWidth(byteWidth));
    this.offset = newOffset;
  }

  private writeBlob(arrayBuffer: ArrayBuffer) {
    const length = arrayBuffer.byteLength;
    const bitWidth = uwidth(length);
    const byteWidth = this.align(bitWidth);
    this.writeUInt(length, byteWidth);
    const blobOffset = this.offset;
    const newOffset = this.computeOffset(length);
    new Uint8Array(this.buffer).set(new Uint8Array(arrayBuffer), blobOffset);
    this.stack.push(
      this.offsetStackValue(blobOffset, ValueType.BLOB, bitWidth),
    );
    this.offset = newOffset;
  }

  private writeString(str: string): void {
    if (
      this.dedupStrings &&
      Object.prototype.hasOwnProperty.call(this.stringLookup, str)
    ) {
      this.stack.push(this.stringLookup[str]);
      return;
    }
    const utf8 = toUTF8Array(str);
    const length = utf8.length;
    const bitWidth = uwidth(length);
    const byteWidth = this.align(bitWidth);
    this.writeUInt(length, byteWidth);
    const stringOffset = this.offset;
    const newOffset = this.computeOffset(length + 1);
    new Uint8Array(this.buffer).set(utf8, stringOffset);
    const stackValue = this.offsetStackValue(
      stringOffset,
      ValueType.STRING,
      bitWidth,
    );
    this.stack.push(stackValue);
    if (this.dedupStrings) {
      this.stringLookup[str] = stackValue;
    }
    this.offset = newOffset;
  }

  private writeKey(str: string): void {
    if (
      this.dedupKeys &&
      Object.prototype.hasOwnProperty.call(this.keyLookup, str)
    ) {
      this.stack.push(this.keyLookup[str]);
      return;
    }
    const utf8 = toUTF8Array(str);
    const length = utf8.length;
    const newOffset = this.computeOffset(length + 1);
    new Uint8Array(this.buffer).set(utf8, this.offset);
    const stackValue = this.offsetStackValue(
      this.offset,
      ValueType.KEY,
      BitWidth.WIDTH8,
    );
    this.stack.push(stackValue);
    if (this.dedupKeys) {
      this.keyLookup[str] = stackValue;
    }
    this.offset = newOffset;
  }

  private writeStackValue(value: StackValue, byteWidth: number): void {
    const newOffset = this.computeOffset(byteWidth);
    if (value.isOffset()) {
      const relativeOffset = this.offset - value.offset;
      if (
        byteWidth === 8 ||
        BigInt(relativeOffset) < BigInt(1) << BigInt(byteWidth * 8)
      ) {
        this.writeUInt(relativeOffset, byteWidth);
      } else {
        throw `Unexpected size ${byteWidth}. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new`;
      }
    } else {
      value.writeToBuffer(byteWidth);
    }
    this.offset = newOffset;
  }

  private integrityCheckOnValueAddition() {
    if (this.finished) {
      throw 'Adding values after finish is prohibited';
    }
    if (
      this.stackPointers.length !== 0 &&
      this.stackPointers[this.stackPointers.length - 1].isVector === false
    ) {
      if (this.stack[this.stack.length - 1].type !== ValueType.KEY) {
        throw 'Adding value to a map before adding a key is prohibited';
      }
    }
  }

  private integrityCheckOnKeyAddition() {
    if (this.finished) {
      throw 'Adding values after finish is prohibited';
    }
    if (
      this.stackPointers.length === 0 ||
      this.stackPointers[this.stackPointers.length - 1].isVector
    ) {
      throw 'Adding key before starting a map is prohibited';
    }
  }

  startVector(): void {
    this.stackPointers.push({stackPosition: this.stack.length, isVector: true});
  }

  startMap(presorted = false): void {
    this.stackPointers.push({
      stackPosition: this.stack.length,
      isVector: false,
      presorted: presorted,
    });
  }

  private endVector(stackPointer: StackPointer) {
    const vecLength = this.stack.length - stackPointer.stackPosition;
    const vec = this.createVector(stackPointer.stackPosition, vecLength, 1);
    this.stack.splice(stackPointer.stackPosition, vecLength);
    this.stack.push(vec);
  }

  private endMap(stackPointer: StackPointer) {
    if (!stackPointer.presorted) {
      this.sort(stackPointer);
    }
    let keyVectorHash = '';
    for (let i = stackPointer.stackPosition; i < this.stack.length; i += 2) {
      keyVectorHash += `,${this.stack[i].offset}`;
    }
    const vecLength = (this.stack.length - stackPointer.stackPosition) >> 1;

    if (
      this.dedupKeyVectors &&
      !Object.prototype.hasOwnProperty.call(this.keyVectorLookup, keyVectorHash)
    ) {
      this.keyVectorLookup[keyVectorHash] = this.createVector(
        stackPointer.stackPosition,
        vecLength,
        2,
      );
    }
    const keysStackValue = this.dedupKeyVectors
      ? this.keyVectorLookup[keyVectorHash]
      : this.createVector(stackPointer.stackPosition, vecLength, 2);
    const valuesStackValue = this.createVector(
      stackPointer.stackPosition + 1,
      vecLength,
      2,
      keysStackValue,
    );
    this.stack.splice(stackPointer.stackPosition, vecLength << 1);
    this.stack.push(valuesStackValue);
  }

  private sort(stackPointer: StackPointer) {
    const view = this.view;
    const stack = this.stack;

    function shouldFlip(v1: StackValue, v2: StackValue) {
      if (v1.type !== ValueType.KEY || v2.type !== ValueType.KEY) {
        throw `Stack values are not keys ${v1} | ${v2}. Check if you combined [addKey] with add... method calls properly.`;
      }
      let c1, c2;
      let index = 0;
      do {
        c1 = view.getUint8(v1.offset + index);
        c2 = view.getUint8(v2.offset + index);
        if (c2 < c1) return true;
        if (c1 < c2) return false;
        index += 1;
      } while (c1 !== 0 && c2 !== 0);
      return false;
    }

    function swap(stack: Array<StackValue>, flipIndex: number, i: number) {
      if (flipIndex === i) return;
      const k = stack[flipIndex];
      const v = stack[flipIndex + 1];
      stack[flipIndex] = stack[i];
      stack[flipIndex + 1] = stack[i + 1];
      stack[i] = k;
      stack[i + 1] = v;
    }

    function selectionSort() {
      for (let i = stackPointer.stackPosition; i < stack.length; i += 2) {
        let flipIndex = i;
        for (let j = i + 2; j < stack.length; j += 2) {
          if (shouldFlip(stack[flipIndex], stack[j])) {
            flipIndex = j;
          }
        }
        if (flipIndex !== i) {
          swap(stack, flipIndex, i);
        }
      }
    }

    function smaller(v1: StackValue, v2: StackValue) {
      if (v1.type !== ValueType.KEY || v2.type !== ValueType.KEY) {
        throw `Stack values are not keys ${v1} | ${v2}. Check if you combined [addKey] with add... method calls properly.`;
      }
      if (v1.offset === v2.offset) {
        return false;
      }
      let c1, c2;
      let index = 0;
      do {
        c1 = view.getUint8(v1.offset + index);
        c2 = view.getUint8(v2.offset + index);
        if (c1 < c2) return true;
        if (c2 < c1) return false;
        index += 1;
      } while (c1 !== 0 && c2 !== 0);
      return false;
    }

    function quickSort(left: number, right: number) {
      if (left < right) {
        const mid = left + ((right - left) >> 2) * 2;
        const pivot = stack[mid];
        let left_new = left;
        let right_new = right;

        do {
          while (smaller(stack[left_new], pivot)) {
            left_new += 2;
          }
          while (smaller(pivot, stack[right_new])) {
            right_new -= 2;
          }
          if (left_new <= right_new) {
            swap(stack, left_new, right_new);
            left_new += 2;
            right_new -= 2;
          }
        } while (left_new <= right_new);

        quickSort(left, right_new);
        quickSort(left_new, right);
      }
    }

    let sorted = true;
    for (
      let i = stackPointer.stackPosition;
      i < this.stack.length - 2;
      i += 2
    ) {
      if (shouldFlip(this.stack[i], this.stack[i + 2])) {
        sorted = false;
        break;
      }
    }

    if (!sorted) {
      if (this.stack.length - stackPointer.stackPosition > 40) {
        quickSort(stackPointer.stackPosition, this.stack.length - 2);
      } else {
        selectionSort();
      }
    }
  }

  end(): void {
    if (this.stackPointers.length < 1) return;
    const pointer = this.stackPointers.pop() as StackPointer;
    if (pointer.isVector) {
      this.endVector(pointer);
    } else {
      this.endMap(pointer);
    }
  }

  private createVector(
    start: number,
    vecLength: number,
    step: number,
    keys: StackValue | null = null,
  ) {
    let bitWidth = uwidth(vecLength);
    let prefixElements = 1;
    if (keys !== null) {
      const elementWidth = keys.elementWidth(this.offset, 0);
      if (elementWidth > bitWidth) {
        bitWidth = elementWidth;
      }
      prefixElements += 2;
    }
    let vectorType = ValueType.KEY;
    let typed = keys === null;
    for (let i = start; i < this.stack.length; i += step) {
      const elementWidth = this.stack[i].elementWidth(
        this.offset,
        i + prefixElements,
      );
      if (elementWidth > bitWidth) {
        bitWidth = elementWidth;
      }
      if (i === start) {
        vectorType = this.stack[i].type;
        typed = typed && isTypedVectorElement(vectorType);
      } else {
        if (vectorType !== this.stack[i].type) {
          typed = false;
        }
      }
    }
    const byteWidth = this.align(bitWidth);
    const fix =
      typed && isNumber(vectorType) && vecLength >= 2 && vecLength <= 4;
    if (keys !== null) {
      this.writeStackValue(keys, byteWidth);
      this.writeUInt(1 << keys.width, byteWidth);
    }
    if (!fix) {
      this.writeUInt(vecLength, byteWidth);
    }
    const vecOffset = this.offset;
    for (let i = start; i < this.stack.length; i += step) {
      this.writeStackValue(this.stack[i], byteWidth);
    }
    if (!typed) {
      for (let i = start; i < this.stack.length; i += step) {
        this.writeUInt(this.stack[i].storedPackedType(), 1);
      }
    }
    if (keys !== null) {
      return this.offsetStackValue(vecOffset, ValueType.MAP, bitWidth);
    }
    if (typed) {
      const vType = toTypedVector(vectorType, fix ? vecLength : 0);
      return this.offsetStackValue(vecOffset, vType, bitWidth);
    }
    return this.offsetStackValue(vecOffset, ValueType.VECTOR, bitWidth);
  }

  private nullStackValue() {
    return new StackValue(this, ValueType.NULL, BitWidth.WIDTH8);
  }

  private boolStackValue(value: boolean) {
    return new StackValue(this, ValueType.BOOL, BitWidth.WIDTH8, value);
  }

  private intStackValue(value: number | bigint) {
    return new StackValue(this, ValueType.INT, iwidth(value), value as number);
  }

  private uintStackValue(value: number) {
    return new StackValue(this, ValueType.UINT, uwidth(value), value);
  }

  private floatStackValue(value: number) {
    return new StackValue(this, ValueType.FLOAT, fwidth(value), value);
  }

  private offsetStackValue(
    offset: number,
    valueType: ValueType,
    bitWidth: BitWidth,
  ): StackValue {
    return new StackValue(this, valueType, bitWidth, null, offset);
  }

  private finishBuffer() {
    if (this.stack.length !== 1) {
      throw `Stack has to be exactly 1, but it is ${this.stack.length}. You have to end all started vectors and maps before calling [finish]`;
    }
    const value = this.stack[0];
    const byteWidth = this.align(value.elementWidth(this.offset, 0));
    this.writeStackValue(value, byteWidth);
    this.writeUInt(value.storedPackedType(), 1);
    this.writeUInt(byteWidth, 1);
    this.finished = true;
  }

  add(
    value:
      | undefined
      | null
      | boolean
      | bigint
      | number
      | DataView
      | string
      | Array<unknown>
      | Record<string, unknown>
      | unknown,
  ): void {
    this.integrityCheckOnValueAddition();
    if (typeof value === 'undefined') {
      throw 'You need to provide a value';
    }
    if (value === null) {
      this.stack.push(this.nullStackValue());
    } else if (typeof value === 'boolean') {
      this.stack.push(this.boolStackValue(value));
    } else if (typeof value === 'bigint') {
      this.stack.push(this.intStackValue(value));
    } else if (typeof value == 'number') {
      if (Number.isInteger(value)) {
        this.stack.push(this.intStackValue(value));
      } else {
        this.stack.push(this.floatStackValue(value));
      }
    } else if (ArrayBuffer.isView(value)) {
      this.writeBlob(value.buffer);
    } else if (typeof value === 'string' || value instanceof String) {
      this.writeString(value as string);
    } else if (Array.isArray(value)) {
      this.startVector();
      for (let i = 0; i < value.length; i++) {
        this.add(value[i]);
      }
      this.end();
    } else if (typeof value === 'object') {
      const properties = Object.getOwnPropertyNames(value).sort();
      this.startMap(true);
      for (let i = 0; i < properties.length; i++) {
        const key = properties[i];
        this.addKey(key);
        this.add((value as Record<string, unknown>)[key]);
      }
      this.end();
    } else {
      throw `Unexpected value input ${value}`;
    }
  }

  finish(): Uint8Array {
    if (!this.finished) {
      this.finishBuffer();
    }
    const result = this.buffer.slice(0, this.offset);
    return new Uint8Array(result);
  }

  isFinished(): boolean {
    return this.finished;
  }

  addKey(key: string): void {
    this.integrityCheckOnKeyAddition();
    this.writeKey(key);
  }

  addInt(value: number, indirect = false, deduplicate = false): void {
    this.integrityCheckOnValueAddition();
    if (!indirect) {
      this.stack.push(this.intStackValue(value));
      return;
    }
    if (
      deduplicate &&
      Object.prototype.hasOwnProperty.call(this.indirectIntLookup, value)
    ) {
      this.stack.push(this.indirectIntLookup[value]);
      return;
    }
    const stackValue = this.intStackValue(value);
    const byteWidth = this.align(stackValue.width);
    const newOffset = this.computeOffset(byteWidth);
    const valueOffset = this.offset;
    stackValue.writeToBuffer(byteWidth);
    const stackOffset = this.offsetStackValue(
      valueOffset,
      ValueType.INDIRECT_INT,
      stackValue.width,
    );
    this.stack.push(stackOffset);
    this.offset = newOffset;
    if (deduplicate) {
      this.indirectIntLookup[value] = stackOffset;
    }
  }

  addUInt(value: number, indirect = false, deduplicate = false): void {
    this.integrityCheckOnValueAddition();
    if (!indirect) {
      this.stack.push(this.uintStackValue(value));
      return;
    }
    if (
      deduplicate &&
      Object.prototype.hasOwnProperty.call(this.indirectUIntLookup, value)
    ) {
      this.stack.push(this.indirectUIntLookup[value]);
      return;
    }
    const stackValue = this.uintStackValue(value);
    const byteWidth = this.align(stackValue.width);
    const newOffset = this.computeOffset(byteWidth);
    const valueOffset = this.offset;
    stackValue.writeToBuffer(byteWidth);
    const stackOffset = this.offsetStackValue(
      valueOffset,
      ValueType.INDIRECT_UINT,
      stackValue.width,
    );
    this.stack.push(stackOffset);
    this.offset = newOffset;
    if (deduplicate) {
      this.indirectUIntLookup[value] = stackOffset;
    }
  }

  addFloat(value: number, indirect = false, deduplicate = false): void {
    this.integrityCheckOnValueAddition();
    if (!indirect) {
      this.stack.push(this.floatStackValue(value));
      return;
    }
    if (
      deduplicate &&
      Object.prototype.hasOwnProperty.call(this.indirectFloatLookup, value)
    ) {
      this.stack.push(this.indirectFloatLookup[value]);
      return;
    }
    const stackValue = this.floatStackValue(value);
    const byteWidth = this.align(stackValue.width);
    const newOffset = this.computeOffset(byteWidth);
    const valueOffset = this.offset;
    stackValue.writeToBuffer(byteWidth);
    const stackOffset = this.offsetStackValue(
      valueOffset,
      ValueType.INDIRECT_FLOAT,
      stackValue.width,
    );
    this.stack.push(stackOffset);
    this.offset = newOffset;
    if (deduplicate) {
      this.indirectFloatLookup[value] = stackOffset;
    }
  }
}
