import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  ManyToOne,
  JoinColumn,
  Index,
} from 'typeorm';
import { Program } from './program.entity';
import { User } from './user.entity';
import { AccessScopeEnum } from '../enum/access-scope.enum';
import { AccessStateEnum } from '../enum/access-state.enum';
import { ProgramStatusEnum } from '../enum/program-status.enum';

/**
 * Entity representing program access user mapping
 * Tracks which users have access to view/register for specific programs
 * Supports audit trail and state transitions
 */
@Entity('program_access_user_map')
@Index(['programId', 'state', 'deletedAt'])
@Index(['userId', 'state', 'deletedAt'])
@Index(['programId', 'userId', 'state', 'deletedAt'], {
  unique: true,
  where: 'deleted_at IS NULL AND state = \'ACTIVE\'',
})
export class ProgramAccessUserMap {
  @PrimaryGeneratedColumn('increment')
  id: number;

  @Column({ name: 'program_id', type: 'int', nullable: false })
  programId: number;

  @ManyToOne(() => Program, { nullable: false })
  @JoinColumn({ name: 'program_id', referencedColumnName: 'id' })
  program: Program;

  @Column({ name: 'user_id', type: 'int', nullable: false })
  userId: number;

  @ManyToOne(() => User, { nullable: false })
  @JoinColumn({ name: 'user_id', referencedColumnName: 'id' })
  user: User;

  @Column({
    name: 'access_scope',
    type: 'enum',
    enum: AccessScopeEnum,
    default: AccessScopeEnum.VIEW_AND_REGISTER,
    nullable: false,
    comment: 'Defines what level of access the user has - VIEW_ONLY or VIEW_AND_REGISTER',
  })
  accessScope: AccessScopeEnum;

  @Column({
    name: 'program_status',
    type: 'enum',
    enum: ProgramStatusEnum,
    nullable: true,
    comment: 'Status of the program at the time of mapping',
  })
  programStatus: ProgramStatusEnum;

  @Column({
    name: 'state',
    type: 'enum',
    enum: AccessStateEnum,
    default: AccessStateEnum.ACTIVE,
    nullable: false,
    comment: 'Current state of the access mapping - ACTIVE or REMOVED',
  })
  state: AccessStateEnum;

  @Column({
    name: 'effective_from',
    type: 'timestamptz',
    nullable: true,
    comment: 'When the access becomes effective. NULL means effective immediately',
  })
  effectiveFrom?: Date;

  @Column({
    name: 'effective_till',
    type: 'timestamptz',
    nullable: true,
    comment: 'When the access expires. NULL means no expiration',
  })
  effectiveTill?: Date;

  @Column({
    name: 'reason',
    type: 'text',
    nullable: true,
    comment: 'Reason for granting or modifying access',
  })
  reason?: string;

  @Column({
    name: 'meta',
    type: 'jsonb',
    nullable: true,
    comment: 'Additional metadata for the mapping',
  })
  meta?: Record<string, any>;

  @Column({ name: 'created_by', type: 'int', nullable: false })
  createdBy: number;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'created_by', referencedColumnName: 'id' })
  creator: User;

  @Column({ name: 'updated_by', type: 'int', nullable: true })
  updatedBy: number;

  @ManyToOne(() => User)
  @JoinColumn({ name: 'updated_by', referencedColumnName: 'id' })
  updater: User;

  @CreateDateColumn({
    name: 'created_at',
    type: 'timestamptz',
    default: () => 'CURRENT_TIMESTAMP',
  })
  createdAt: Date;

  @UpdateDateColumn({
    name: 'updated_at',
    type: 'timestamptz',
    default: () => 'CURRENT_TIMESTAMP',
  })
  updatedAt: Date;

  @DeleteDateColumn({
    name: 'deleted_at',
    type: 'timestamptz',
    nullable: true,
    comment: 'Soft delete timestamp',
  })
  deletedAt: Date;

  constructor(partial: Partial<ProgramAccessUserMap>) {
    Object.assign(this, partial);
  }
}
