interface InquiryField {
  readonly type: string;
}

export type RawInquiryField = {
  type: string;
  value?: any;
};

export namespace InquiryField {
  export class Integer implements InquiryField {
    readonly type: string = 'integer';
    readonly value?: number;

    constructor(value?: number) {
      this.value = value;
    }
  }

  export class String implements InquiryField {
    readonly type: string = 'string';
    readonly value?: string;

    constructor(value?: string) {
      this.value = value;
    }
  }

  export class Boolean implements InquiryField {
    readonly type: string = 'boolean';
    readonly value?: boolean;

    constructor(value?: boolean) {
      this.value = value;
    }
  }

  export class Unknown implements InquiryField {
    readonly type: string;

    constructor(type: string) {
      this.type = type;
    }
  }

  export function parse({ type, value }: RawInquiryField): InquiryField | null {
    if (value == null) {
      return null;
    }
    switch (type) {
      case 'integer':
        return new InquiryField.Integer(Number.parseInt(value));
      case 'string':
        return new InquiryField.String(value);
      case 'boolean':
        return new InquiryField.Boolean(JSON.parse(value));
      case 'unknown':
        return new InquiryField.Unknown(value);
      default:
        return new InquiryField.Unknown(type);
    }
  }
}

export type Fields = Record<string, InquiryField | null>;

export namespace Fields {
  export function builder(): Builder {
    return new Fields.Builder();
  }

  export class Builder {
    private _fields: Record<string, InquiryField>;

    constructor() {
      this._fields = {};
    }

    public integer(fieldKey: string, value?: number) {
      this._fields = {
        ...this._fields,
        [fieldKey]: new InquiryField.Integer(value),
      };

      return this;
    }

    public boolean(fieldKey: string, value?: boolean) {
      this._fields = {
        ...this._fields,
        [fieldKey]: new InquiryField.Boolean(value),
      };

      return this;
    }

    public string(fieldKey: string, value?: string) {
      this._fields = {
        ...this._fields,
        [fieldKey]: new InquiryField.String(value),
      };

      return this;
    }

    public build(): Fields {
      return this._fields;
    }
  }
}
