// @link http://acme-schemas.triniti.io/json-schema/acme/people/node/person/1-0-0.json#
import Fb from '@gdbots/pbj/FieldBuilder';
import Format from '@gdbots/pbj/enums/Format';
import GdbotsNcrNodeV1Mixin from '@gdbots/schemas/gdbots/ncr/mixin/node/NodeV1Mixin';
import Message from '@gdbots/pbj/Message';
import NodeStatus from '@gdbots/schemas/gdbots/ncr/enums/NodeStatus';
import Schema from '@gdbots/pbj/Schema';
import T from '@gdbots/pbj/types';
import TrinitiPeoplePersonV1Mixin from '@triniti/schemas/triniti/people/mixin/person/PersonV1Mixin';
import UuidIdentifier from '@gdbots/pbj/well-known/UuidIdentifier';

export default class PersonV1 extends Message {
  /**
   * @private
   *
   * @returns {Schema}
   */
  static defineSchema() {
    return new Schema(this.SCHEMA_ID, this,
      [
        /*
         * The "_id" value:
         * - MUST NOT change for the life of the node.
         * - SHOULD be globally unique
         * - SHOULD be generated by the app (ideally in default value closure... e.g. UuidIdentifier::generate())
         */
        Fb.create('_id', T.IdentifierType.create())
          .required()
          .withDefault(() => UuidIdentifier.generate())
          .classProto(UuidIdentifier)
          .overridable(true)
          .build(),
        Fb.create('status', T.StringEnumType.create())
          .withDefault("draft")
          .classProto(NodeStatus)
          .build(),
        Fb.create('etag', T.StringType.create())
          .maxLength(100)
          .pattern('^[\\w\\.:-]+$')
          .build(),
        Fb.create('created_at', T.MicrotimeType.create())
          .build(),
        /*
         * A fully qualified reference to what created this node. This is intentionally a message-ref
         * and not a user id because it is often a program that creates nodes, not a user.
         */
        Fb.create('creator_ref', T.MessageRefType.create())
          .build(),
        Fb.create('updated_at', T.MicrotimeType.create())
          .useTypeDefault(false)
          .build(),
        /*
         * A fully qualified reference to what updated this node. This is intentionally a message-ref
         * and not a user id because it is often a program that updates nodes, not a user.
         * E.g. "acme:iam:node:app:cli-scheduler" or "acme:iam:node:user:60c71df0-fda8-11e5-bfb9-30342d363854"
         */
        Fb.create('updater_ref', T.MessageRefType.create())
          .build(),
        /*
         * A reference to the last event that changed the state of this node.
         * E.g. "acme:blog:event:article-published:60c71df0-fda8-11e5-bfb9-30342d363854"
         */
        Fb.create('last_event_ref', T.MessageRefType.create())
          .build(),
        Fb.create('title', T.StringType.create())
          .build(),
        /*
         * A reference to the image asset to use for widgets, sharing, seo.
         */
        Fb.create('image_ref', T.NodeRefType.create())
          .build(),
        /*
         * A short bio of the person. It should typically not have HTML as it is
         * used in metadata, feeds, SERP and social.
         */
        Fb.create('bio', T.TextType.create())
          .build(),
        /*
         * Indicates where the bio data originated from, e.g. imdb, freebase, custom.
         */
        Fb.create('bio_source', T.StringType.create())
          .format(Format.SLUG)
          .build(),
        Fb.create('imdb_url', T.TextType.create())
          .format(Format.URL)
          .build(),
        Fb.create('twitter_username', T.StringType.create())
          .pattern('^\\w{1,15}$')
          .build(),
        Fb.create('is_celebrity', T.BooleanType.create())
          .build(),
        /*
         * Tags is a map that categorizes data or tracks references in
         * external systems. The tags names should be consistent and descriptive,
         * e.g. fb_user_id:123, salesforce_customer_id:456.
         */
        Fb.create('tags', T.StringType.create())
          .asAMap()
          .pattern('^[\\w\\/\\.:-]+$')
          .build(),
        /*
         * The "slug" is a secondary identifier, typically used in a url:
         * - MUST be url friendly
         * - SHOULD NOT be case sensitive
         * - SHOULD be unique within the message curie namespace
         * - CAN be changed, but in practice once nodes are published you should avoid it if possible
         */
        Fb.create('slug', T.StringType.create())
          .format(Format.SLUG)
          .build(),
        Fb.create('blocks', T.MessageType.create())
          .asAList()
          .anyOfCuries([
            'triniti:canvas:mixin:block',
          ])
          .build(),
        Fb.create('ads_enabled', T.BooleanType.create())
          .withDefault(true)
          .build(),
        Fb.create('dfp_ad_unit_path', T.StringType.create())
          .pattern('^[\\w\\/\\.:-]+$')
          .build(),
        Fb.create('dfp_cust_params', T.StringType.create())
          .asAMap()
          .pattern('^[\\w\\/\\.:-]+$')
          .build(),
        Fb.create('seo_title', T.StringType.create())
          .build(),
        /*
         * A reference to the image asset to use for SEO instead of
         * the usual image_ref.
         */
        Fb.create('seo_image_ref', T.NodeRefType.create())
          .build(),
        /*
         * Allows customization of the publish date for SEO purposes.
         */
        Fb.create('seo_published_at', T.DateTimeType.create())
          .build(),
        /*
         * Allows customization of the updated date for SEO purposes. For example
         * if something meaningful is updated this date should be used instead of
         * the node's normal updated_at field which accounts for every change.
         */
        Fb.create('seo_updated_at', T.DateTimeType.create())
          .build(),
        Fb.create('meta_description', T.TextType.create())
          .maxLength(5000)
          .build(),
        Fb.create('meta_keywords', T.StringType.create())
          .asASet()
          .build(),
        /*
         * Unlisted content will not show up in any search results
         * but can still be viewed if you know the URL.
         */
        Fb.create('is_unlisted', T.BooleanType.create())
          .build(),
        /*
         * A string used to indicate that a visual treatment should be
         * applied to a piece of content, e.g. "christmas" or "taco".
         */
        Fb.create('theme', T.StringType.create())
          .format(Format.SLUG)
          .build(),
        /*
         * Determines the sequence that this teaserable node will be rendered
         * in lists, search results, etc. It DOES NOT control visibility or
         * publishing. A date was used over an integer (e.g. seq_no) for
         * blog-like, reverse chronological, clarity in sorting.
         */
        Fb.create('order_date', T.DateTimeType.create())
          .build(),
        Fb.create('hashtags', T.StringType.create())
          .asASet()
          .format(Format.HASHTAG)
          .build(),
      ],
      this.MIXINS,
    );
  }
}

const M = PersonV1;
M.prototype.SCHEMA_ID = M.SCHEMA_ID = 'pbj:acme:people:node:person:1-0-0';
M.prototype.SCHEMA_CURIE = M.SCHEMA_CURIE = 'acme:people:node:person';
M.prototype.SCHEMA_CURIE_MAJOR = M.SCHEMA_CURIE_MAJOR = 'acme:people:node:person:v1';
M.prototype.MIXINS = M.MIXINS = [
  'gdbots:ncr:mixin:node:v1',
  'gdbots:ncr:mixin:node',
  'triniti:people:mixin:person:v1',
  'triniti:people:mixin:person',
  'gdbots:common:mixin:taggable:v1',
  'gdbots:common:mixin:taggable',
  'gdbots:ncr:mixin:sluggable:v1',
  'gdbots:ncr:mixin:sluggable',
  'triniti:canvas:mixin:has-blocks:v1',
  'triniti:canvas:mixin:has-blocks',
  'triniti:common:mixin:advertising:v1',
  'triniti:common:mixin:advertising',
  'triniti:common:mixin:seo:v1',
  'triniti:common:mixin:seo',
  'triniti:common:mixin:themeable:v1',
  'triniti:common:mixin:themeable',
  'triniti:curator:mixin:teaserable:v1',
  'triniti:curator:mixin:teaserable',
  'triniti:taxonomy:mixin:hashtaggable:v1',
  'triniti:taxonomy:mixin:hashtaggable',
];

GdbotsNcrNodeV1Mixin(M);

TrinitiPeoplePersonV1Mixin(M);

Object.freeze(M);
Object.freeze(M.prototype);
