import { Column, Entity, JoinTable, ManyToMany, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { PercentCheck } from '../decorators/percent-check';
import { CollectionPart } from './collection-part';
import { Copy } from './copy';
import { Language } from './language';
import { Transformation } from './transformation';
import { WorkAuthor } from './work-author';
import { WorkCharacter } from './work-character';
import { WorkName } from './work-name';
import { WorkTag } from './work-tag';
import { World } from './world';

/**
 * This is the main library entity.
 *
 * It describes a work of art organized by this software.
 */
@Entity()
@PercentCheck('rating')
export class Work implements IIdentifiableEntity, IMultiNamedEntity {
  @PrimaryGeneratedColumn()
  public id!: number;

  @Column({
    nullable: false,
    default: '',
  })
  public nameCanonical!: string;

  @OneToMany(() => WorkName, (workName: WorkName) => workName.entity)
  public names!: Promise<WorkName[]>;

  /**
   * digital representations of this work
   */
  @OneToMany(() => Copy, (copy: Copy) => copy.original)
  public copies!: Promise<Copy[]>;

  /**
   * other works this work is a transformation of
   */
  @OneToMany(() => Transformation, (transformation: Transformation) => transformation.byWork)
  public transformationOf!: Promise<Transformation[]>;

  /**
   * other works this work is transformed by
   */
  @OneToMany(() => Transformation, (transformation: Transformation) => transformation.ofWork)
  public transformedBy!: Promise<Transformation[]>;

  /**
   * the authors/publishers of this work
   */
  @OneToMany(() => WorkAuthor, (workAuthor: WorkAuthor) => workAuthor.work)
  public workAuthors!: Promise<WorkAuthor[]>;

  /**
   * tags describing this work
   */
  @OneToMany(() => WorkTag, (workTag: WorkTag) => workTag.work)
  public workTags!: Promise<WorkTag[]>;

  /**
   * characters in this work
   */
  @ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.works)
  @JoinTable()
  public workCharacters!: Promise<WorkCharacter[]>;

  /**
   * fictional worlds in which this work takes place
   */
  @ManyToMany(() => World, (world: World) => world.works)
  @JoinTable()
  public worlds!: Promise<World[]>;

  /**
   * if this work i canon in above fictional world
   */
  @Column({
    nullable: false,
    default: false,
  })
  public isCanonical!: boolean;

  /**
   * the user rating of this work
   */
  @Column('int', {
    nullable: true,
  })
  public rating!: number | null;

  /**
   * the release date of the work
   */
  @Column('date', {
    nullable: true,
  })
  public releaseDate!: Date | null;

  /**
   * the languages of the work (if applicable)
   */
  @ManyToMany(() => Language, (language: Language) => language.works)
  @JoinTable()
  public languages!: Promise<Language[]>;

  /**
   * the collections this work is a part of
   */
  @OneToMany(() => CollectionPart, (collectionPart: CollectionPart) => collectionPart.work)
  public collectionParts!: Promise<CollectionPart[]>;
}
