import { Api, RouteOptions } from './Api';
import { ApiGateway } from './ApiGateway';
import { Func } from '../types/Func';
import { Uri } from '../types/Uri';
import { PageList } from '../types/PageList';
import { Json, JsonValue } from '../types/Json';
import { Id } from '../types/Id';
import { Optional } from '../types/Types';
import { List } from '../types/List';
import { toArray } from '../types/Array';
import { HttpStatus } from '../http/HttpStatus';

export class RouteGateway extends ApiGateway {
  constructor(
    readonly route: Func<Uri>,
    readonly routeId: Func<Uri>,
    readonly api: Api = new Api()
  ) {
    super(api);
  }

  all(options?: RouteOptions): Promise<PageList<Json>> {
    return this.get(this.route(), options);
  }

  byId(id: Id, options?: RouteOptions): Promise<Optional<Json>> {
    return this.getOne(this.routeId().id(id));
  }

  byIds(...ids: Id[]): Promise<List<Json>> {
    return this.get(this.route().ids(toArray(...ids)));
  }

  search(q: JsonValue, options?: RouteOptions): Promise<PageList<Json>> {
    return this.get(this.route().query(q), options);
  }

  exists(id: Id, options?: RouteOptions): Promise<boolean> {
    return this.get(this.routeId().id(id))
      .then(r => r.length === 1)
      .catch(r => (HttpStatus.NotFound.equals(r.status) ? false : Promise.reject(r)));
  }

  add(item: Json, options?: RouteOptions): Promise<Json> {
    return this.post(this.route(), item, options);
  }

  filter(options?: RouteOptions): Promise<PageList<Json>> {
    return this.postSearch(this.route(), options);
  }

  update(item: Json, options?: RouteOptions): Promise<Json> {
    return this.patch(this.routeId().id(item.id), item, options);
  }

  upsert(item: Json, options?: RouteOptions): Promise<Json> {
    return this.put(this.routeId().id(item.id), item, options);
  }

  remove(id: Id, options?: RouteOptions): Promise<boolean> {
    return this.delete(this.routeId().id(id), options);
  }
}
