import {
  IsBoolean,
  IsInt,
  IsNotEmpty,

  IsPositive
} from "class-validator";
import { BeforeInsert, BeforeUpdate, Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
import { ResponseScan } from '../responses/ResponseScan';
import type { Runner } from "./Runner";

/**
 * Defines the Scan entity.
 * A scan basicly adds a certain distance to a runner's total ran distance.
 */
@Entity()
@TableInheritance({ column: { name: "type", type: "varchar" } })
@Index(['runner'])
@Index(['runner', 'created_at'])
@Index(['valid'])
export class Scan {
  /**
   * Autogenerated unique id (primary key).
   */
  @PrimaryGeneratedColumn()
  @IsInt()
  id: number;

  /**
   * The scan's associated runner.
   * This is important to link ran distances to runners.
   */
  @IsNotEmpty()
  @ManyToOne(() => require("./Runner").Runner, (runner: Runner) => runner.scans, { nullable: false })
  runner!: Runner;

  /**
   * Is the scan valid (for fraud reasons).
   * The determination of validity will work differently for every child class.
   * Default: true
   */
  @Column()
  @IsBoolean()
  valid: boolean = true;

  @Column({ type: 'bigint', nullable: true, readonly: true })
  @IsInt()
  @IsPositive()
  created_at: number;

  @Column({ type: 'bigint', nullable: true })
  @IsInt()
  @IsPositive()
  updated_at: number;

  @BeforeInsert()
  public setCreatedAt() {
    this.created_at = Math.floor(Date.now() / 1000);
    this.updated_at = Math.floor(Date.now() / 1000);
  }

  @BeforeUpdate()
  public setUpdatedAt() {
    this.updated_at = Math.floor(Date.now() / 1000);
  }

  /**
   * The scan's distance in meters.
   * This is the "real" value used by "normal" scans..
   */
  @Column({ nullable: true })
  @IsInt()
  private _distance?: number;

  /**
   * The scan's distance in meters.
   * Can be set manually or derived from another object.
   */
  @IsInt()
  @IsPositive()
  public get distance(): number {
    return this._distance;
  }

  /**
   * The scan's distance in meters.
   * Can be set manually or derived from another object.
   */
  public set distance(value: number) {
    this._distance = value;
  }

  /**
   * Turns this entity into it's response class.
   */
  public toResponse(): ResponseScan {
    return new ResponseScan(this);
  }
}