import { Buffer } from 'buffer';
import { NTLMFlag, NTLMTypeFlags } from './core';
import { getSecBuf, getSecBufData } from '../ntlm-parser/parser-utils';

export interface Type1MessageOptions {
  readonly domain: string;
  readonly workstation: string;
}

export const getSuppliedDomainData = (messageType1: Buffer): string => {
  const buf = messageType1.buffer.slice(messageType1.byteOffset, messageType1.byteOffset + messageType1.byteLength) as ArrayBuffer;
  const suppliedDomain = getSecBuf(buf as ArrayBuffer, 16);
  return getSecBufData(buf as ArrayBuffer, suppliedDomain, 'ascii');
};

export const createMessageType1Buf = (options: Type1MessageOptions): Buffer => {
  const domain = encodeURIComponent(options.domain.toUpperCase());
  const workstation = encodeURIComponent(options.workstation.toUpperCase());
  const protocol = 'NTLMSSP\0';

  const BODY_LENGTH = 40;

  let type1flags = NTLMTypeFlags.TYPE1_FLAGS;
  if (!domain || domain === '') type1flags -= NTLMFlag.NegotiateOemDomainSupplied;

  let pos = 0;
  const buf = Buffer.alloc(BODY_LENGTH + domain.length + workstation.length);

  // protocol
  pos += buf.write(protocol, pos, protocol.length);
  // type 1
  pos = buf.writeUInt32LE(1, pos);
  // TYPE1 flag
  pos = buf.writeUInt32LE(type1flags, pos);

  // domain length
  pos = buf.writeUInt16LE(domain.length, pos);
  // domain max length
  pos = buf.writeUInt16LE(domain.length, pos);
  // domain buffer offset
  pos = buf.writeUInt32LE(BODY_LENGTH + workstation.length, pos);

  // workstation length
  pos = buf.writeUInt16LE(workstation.length, pos);
  // workstation max length
  pos = buf.writeUInt16LE(workstation.length, pos);
  // workstation buffer offset
  pos = buf.writeUInt32LE(BODY_LENGTH, pos);

  // ProductMajorVersion
  pos = buf.writeUInt8(5, pos);
  // ProductMinorVersion
  pos = buf.writeUInt8(1, pos);
  // ProductBuild
  pos = buf.writeUInt16LE(2600, pos);

  // VersionReserved1
  pos = buf.writeUInt8(0, pos);
  // VersionReserved2
  pos = buf.writeUInt8(0, pos);
  // VersionReserved3
  pos = buf.writeUInt8(0, pos);
  // NTLMRevisionCurrent
  pos = buf.writeUInt8(15, pos);

  // length checks is to fix issue #46 and possibly #57
  if (workstation.length !== 0) {
    // workstation string
    pos += buf.write(workstation, pos, workstation.length, 'ascii');
  }

  if (domain.length !== 0) {
    // domain string
    buf.write(domain, pos, domain.length, 'ascii');
  }

  return buf;
};

export const createMessageType1 = (options: Type1MessageOptions): string => {
  const buf = createMessageType1Buf(options);
  return `NTLM ${buf.toString('base64')}`;
};
