import { pond } from "protobuf-ts/pond";
import { or } from "../utils/types";
import { cloneDeep } from "lodash";

const adminActions = [
  "provision",
  "upload-firmware",
  "remove-devices",
  "copy-token",
  "recluse",
  "pause-data"
];

const adminFeatures = [
  "beta",
  "billing",
  "security",
  "dev-channel",
  "docs",
  "maps",
  "sleep",
  "support",
  "json",
  "tasks",
  "teams",
  "developer",
  "installer"
];

export class User {
  public settings: pond.UserSettings = pond.UserSettings.create();
  public status: pond.UserStatus = pond.UserStatus.create();
  public permissions: pond.Permission[] = [];
  public preferences: pond.UserPreferences = pond.UserPreferences.create();

  public static create(pb?: pond.User): User {
    let my = new User();
    if (pb) {
      my.settings = pond.UserSettings.fromObject(cloneDeep(or(pb.settings, {})));
      my.status = pond.UserStatus.fromObject(cloneDeep(or(pb.status, {})));
      my.permissions = cloneDeep(pb.permissions);
      my.preferences = pond.UserPreferences.fromObject(cloneDeep(or(pb.preferences, {})));
    }
    return my;
  }

  public static any(data: any): User {
    return User.create(pond.User.fromObject(cloneDeep(data)));
  }

  public empty(): boolean {
    return this.id() === "";
  }

  public id(): string {
    return this.settings.id;
  }

  public name(): string {
    return this.settings.name !== "" ? this.settings.name : "User " + this.settings.id;
  }

  public static clone(other?: User): User {
    if (other) {
      return User.create(
        pond.User.fromObject({
          settings: pond.UserSettings.fromObject(cloneDeep(or(other.settings, {}))),
          status: pond.UserStatus.fromObject(cloneDeep(or(other.status, {}))),
          permissions: cloneDeep(other.permissions),
          preferences: pond.UserPreferences.fromObject(cloneDeep(or(other.preferences, {})))
        })
      );
    }
    return User.create();
  }

  public protobuf(): pond.User {
    return pond.User.fromObject({
      settings: this.settings,
      status: this.status
    });
  }

  public hasAdmin(): boolean {
    if (this.settings.features.includes("admin")) {
      return true;
    }
    return false;
  }

  public allowedTo(action: string): boolean {
    if (this.hasAdmin() && adminActions.includes(action)) {
      return true;
    }
    return this.settings.actions.includes(action);
  }

  public hasFeature(flag: string): boolean {
    if (this.hasAdmin() && adminFeatures.includes(flag)) {
      return true;
    }
    return this.settings.features.includes(flag);
  }
}
