import {
  IsBoolean,
  IsInt,
  IsNotEmpty,
  IsOptional,
  IsPositive,
  IsString
} from "class-validator";
import { BeforeInsert, BeforeUpdate, Column, Entity, Index, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { ResponseScanStation } from '../responses/ResponseScanStation';
import type { Track } from "./Track";
import type { TrackScan } from "./TrackScan";

/**
 * Defines the ScanStation entity.
 * ScanStations get used to create TrackScans for runners based on a scan of their runnerCard.
 */
@Entity()
@Index(['track'])
@Index(['prefix'])
@Index(['enabled'])
export class ScanStation {
  /**
   * Autogenerated unique id (primary key).
   */
  @PrimaryGeneratedColumn()
  @IsInt()
  id: number;

  /**
   * The station's description.
   * Mostly for better UX when traceing back stuff.
   */
  @Column({ nullable: true })
  @IsOptional()
  @IsString()
  description?: string;

  /**
   * The track this station is associated with.
   * All scans created by this station will also be associated with this track.
   */
  @IsNotEmpty()
  @ManyToOne(() => require("./Track").Track, (track: Track) => track.stations, { nullable: false })
  track!: Track;

  /**
   * The client's api key prefix.
   * This is used identitfy a client by it's api key.
   */
  @Column({ unique: true })
  @IsString()
  prefix: string;

  /**
   * The station's api key.
   * This is used to authorize a station against the api (not implemented yet).
   */
  @Column()
  @IsNotEmpty()
  @IsString()
  key: string;

  /**
   * The client's api key in plain text.
   * This will only be used to display the full key on creation and updates.
   */
  @IsString()
  @IsOptional()
  cleartextkey?: string;

  /**
   * Used to link track scans to a scan station.
   */
  @OneToMany(() => require("./TrackScan").TrackScan, (scan: TrackScan) => scan.station, { nullable: true })
  scans!: TrackScan[];

  /**
  * Is this station enabled?
  */
  @Column({ nullable: true })
  @IsBoolean()
  enabled?: 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);
  }

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