import {
  BaseModel,
  {{#has.bool}}BooleanField,{{/has.bool}}
  {{#has.float}}FloatField,{{/has.float}}
  {{#has.int}}IntField,{{/has.int}}
  {{#has.numeric}}NumericField,{{/has.numeric}}
  {{#has.json}}JSONField,{{/has.json}}
  {{#has.bytes}}BytesField,{{/has.bytes}}
  {{#has.date}}DateTimeField,{{/has.date}}
  Model,
  {{#has.mto}}ManyToOne,{{/has.mto}}
  {{#has.mtm}}ManyToMany,{{/has.mtm}}
  {{#has.otm}}OneToMany,{{/has.otm}}
  {{#has.oto}}OneToOne, OneToOneJoin,{{/has.oto}}
  {{#has.array}}CustomField,{{/has.array}}
  {{#has.enum}}EnumField,{{/has.enum}}
  StringField,
  JSONField,
} from '@joystream/warthog';  {{! we don't need extra twists here }}

{{#has.numeric}} import BN from 'bn.js' {{/has.numeric}}

{{#has.union}}
import { Column } from 'typeorm';
import { Field } from 'type-graphql';
import { WarthogField } from '@joystream/warthog';
{{/has.union}}

{{#variantImports}} {{{.}}} {{/variantImports}}

{{#isInterface}}
import { InterfaceType } from 'type-graphql';
{{/isInterface}}

{{#has.mtm}}import { JoinTable } from 'typeorm';{{/has.mtm}}

{{#relatedEntityImports}}
  {{{ . }}}
{{/relatedEntityImports}}

import * as jsonTypes from '../jsonfields/jsonfields.model';

{{#enums}}
  import { {{name}} } from '../enums/enums';
  export { {{name}} }; {{! we need to re-export enums for type-GraphQL to resolve types correctly }}
{{/enums}}

{{#interfaces}}
  import { {{className}} } from '../{{kebabName}}/{{kebabName}}.model';
{{/interfaces}}

{{^isInterface}}
@Model({ api: { {{#interfaces}}implements: {{className}},{{/interfaces}} {{#description}} description: `{{{description}}}`{{/description}} }}) {{! only a single interface can be here }}
{{/isInterface}}
{{#isInterface}}
@InterfaceType({{#description}} { description: `{{{description}}}` } {{/description}})
{{/isInterface}}
export class {{className}} {{^isInterface}}extends BaseModel{{/isInterface}} {

{{#fields}}
  {{#is.otm}}
    @OneToMany(
      () => {{relation.columnType}}, (param: {{relation.columnType}}) => param.{{relation.relatedTsProp}},
      {
        {{#relation.nullable}}nullable: true,{{/relation.nullable}}
        modelName: '{{entityName}}',
        relModelName: '{{relation.columnType}}',
        propertyName: '{{camelName}}'
      }
    )
    {{camelName}}?: {{relation.columnType}}[];  
  {{/is.otm}}

  {{#is.mto}}
    @ManyToOne(
      () => {{relation.columnType}},
      {{#relation.relatedTsProp}}(param: {{relation.columnType}}) => param.{{relation.relatedTsProp}},{{/relation.relatedTsProp}}
      {
        skipGraphQLField: true,
        {{#relation.nullable}}nullable: true,{{/relation.nullable}}
        modelName: '{{entityName}}',
        relModelName: '{{relation.columnType}}',
        propertyName: '{{camelName}}'
      }
    )
    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{relation.columnType}};
  {{/is.mto}}

  {{#is.oto}}
    {{^relation.joinColumn}}@OneToOne{{/relation.joinColumn}}
    {{#relation.joinColumn}}@OneToOneJoin{{/relation.joinColumn}}
    (
      () => {{relation.columnType}},
      (param: {{relation.columnType}}) => param.{{relation.relatedTsProp}},
      {
        {{#relation.nullable}}nullable: true,{{/relation.nullable}}
        modelName: '{{entityName}}',
        relModelName: '{{relation.columnType}}',
        propertyName: '{{camelName}}',
      }
    )
    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{relation.columnType}};
  {{/is.oto}}

  {{#is.mtm}}
    @ManyToMany(
      () => {{relation.columnType}},
      (param: {{relation.columnType}}) => param.{{relation.relatedTsProp}},
      {
        {{#relation.nullable}},{ nullable: true }{{/relation.nullable}}
        modelName: '{{entityName}}',
        relModelName: '{{relation.columnType}}',
        propertyName: '{{camelName}}',
      }
    )
    {{#relation.joinTable}}
      @JoinTable({
        name: '{{relation.joinTable.tableName}}',
        joinColumn: {name: '{{relation.joinTable.joinColumn}}' },
        inverseJoinColumn: {name: '{{relation.joinTable.inverseJoinColumn}}' }
      })
    {{/relation.joinTable}}
    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{relation.columnType}}[];
  {{/is.mtm}}
  
  {{#is.array}}
    @CustomField({
      db: { type: '{{dbType}}', array: true,{{^required}}nullable: true,{{/required}} {{#unique}}unique: true,{{/unique}}}, 
      api: { type: '{{apiType}}', {{^required}}nullable: true,{{/required}}
        {{#description}}description: `{{{description}}}`{{/description}} }
    })
    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{tsType}}[];
  {{/is.array}}

  {{! TODO: add enums here }}
  {{#is.scalar}}
    @{{decorator}}({
      {{^required}}nullable: true,{{/required}}
      {{#description}}description: `{{{description}}}`,{{/description}}
      {{#unique}}unique: true,{{/unique}}
      {{#transformer}} transformer: {{{transformer}}}, {{/transformer}}
    })
    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{tsType}};
  {{/is.scalar}}

  {{#is.enum}}
    @EnumField('{{tsType}}', {{tsType}}, { 
      {{^required}}nullable: true,{{/required}} 
      {{#description}}description: `{{{description}}}`{{/description}}
      {{#apiOnly}}, apiOnly: true {{/apiOnly}} })
    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}:{{tsType}} 
  {{/is.enum}}


  {{#is.union}} 
	@Column({{#required}}'jsonb'{{/required}}{{^required}}{ type: 'jsonb', nullable: true }{{/required}})
	@WarthogField('json')
	@Field(type => {{tsType}}, {
      {{^required}}nullable: true,{{/required}} 
      {{#description}}description: `{{{description}}}`{{/description}} })
	{{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: typeof {{tsType}}
  {{/is.union}}

  {{#is.json}}
  @JSONField({filter: true, gqlFieldType: jsonTypes.{{tsType}}, {{^required}}nullable: true,{{/required}} })
  {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: jsonTypes.{{tsType}}
  {{/is.json}}

{{/fields}}

{{^isInterface}}
  constructor(init?: Partial<{{className}}>) {
		super();
		Object.assign(this, init);
	}
{{/isInterface}}
}
