import {
  BaseModel,
  BooleanField,
  DateField,
  FloatField,
  IntField,
  NumericField,
  JSONField,
  BytesField,
  EnumField,
  StringField,
  BigInt
} from '@joystream/warthog';

import {
  Float,
  Int,
  GraphQLISODateTime,
} from 'type-graphql';
import BN from 'bn.js'

{{#imports}} 
{{{.}}};
{{/imports}}

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { GraphQLJSONObject } = require('graphql-type-json');


{{#variants}}
  {{#fields}}
      {{#is.enum}}
        import { {{tsType}} } from '../enums/enums';
        export { {{tsType}} }
      {{/is.enum}}
  {{/fields}}
{{/variants}}

import { ObjectType, Field, createUnionType } from 'type-graphql';
import { getRepository, In } from 'typeorm'

{{#variants}}
@ObjectType()
export class {{name}} {
	public isTypeOf: string = '{{name}}';

  {{#fields}}

    {{#is.entity}}
      @Field(() => {{^array}}{{tsType}}{{/array}} {{#array}}[{{tsType}}]{{/array}}, {
        nullable: true,
        {{#description}}description: `{{{description}}}`{{/description}}
      })
      {{camelName}}?:{{tsType}}{{#array}}[]{{/array}};
      
      // `id` of the related entity, it is required to make the relationship possible.
      @StringField({ dbOnly: true {{#array}},array: true{{/array}} })
      {{camelName}}Id{{#array}}s{{/array}}!: string{{#array}}[]{{/array}};
    {{/is.entity}}

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


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

    {{#is.primitive}}
    @Field(() => {{gqlType}}{{#required}}!{{/required}}, {
        {{^required}}nullable: true,{{/required}}
        {{#description}}description: `{{{description}}}`{{/description}}
    })
    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}:{{tsType}}{{#array}}[]{{/array}};
    {{/is.primitive}}

  {{/fields}}

  {{#fields}}
    {{#is.entity}}
      static async fetchData{{camelName}}(records: any, unionFieldName: string) {
        {{#array}}
          const data: any = {}
          const ids: any[] = []
          records = records.filter(
            (r: any) => (r[unionFieldName] as {{name}}).{{camelName}}Ids && (r[unionFieldName] as {{name}}).{{camelName}}Ids.length
          )
          records.map((r: any) => ids.push(...(r[unionFieldName] as {{name}}).{{camelName}}Ids))

          const relationData = await getRepository({{tsType}}).find({
            where: { id: In(ids) }
          })
          relationData.map((r: any) => data[r.id] = r);

          for (const record of records) {
            
            for (const id of (record[unionFieldName] as {{name}}).{{camelName}}Ids) {
              const m = data[id]
              if (m) {
                if (!(record[unionFieldName] as {{name}}).{{camelName}}) {
                  (record[unionFieldName] as {{name}}).{{camelName}} = []
                }
                record[unionFieldName].{{camelName}}!.push(data[id])
              }
            }
          }
        {{/array}}

        {{^array}}
          const data: any = {}
          const relationData = await getRepository({{tsType}}).find({
            where: { id: In(records.map((r: any) => (r[unionFieldName] as {{name}})?.{{camelName}}Id)) }
          });
          relationData.map((r: any) => data[r.id] = r);

          for (const record of records) {
            const m = data[(record[unionFieldName] as {{name}})?.{{camelName}}Id]
            if (m) {
              (record[unionFieldName] as {{name}}).{{camelName}} = m
            }
          }
        {{/array}}
        return records
      }
    {{/is.entity}}
  {{/fields}}
}
{{/variants}}

{{#unions}}
export const {{name}} = createUnionType({
	name: '{{name}}',
	types: () => [ {{#types}} {{name}}, {{/types}} ],
	resolveType: value => (value.isTypeOf ? value.isTypeOf : undefined)
});
{{/unions}}
