import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  DeleteDateColumn,
  ManyToOne,
  JoinColumn,
  Index,
} from 'typeorm';
import { User } from './user.entity';
import { ProgramRegistration } from './program-registration.entity';
import { OnlineSession } from './online-session.entity';
import { SessionProviderType } from '../enum/session-provider.enum';
import { OnlineSessionRegistrationStatus } from '../enum/online-session-registration-status.enum';
import { RegistrationOnlineSessionActivationStatus } from '../enum/registration-online-session-activation-status.enum';
import { RegistrationOnlineSessionActivationSource } from '../enum/registration-online-session-activation-source.enum';
import { Auditable } from 'src/audit-history/decorators/auditable.decorator';
import { SkipAudit } from 'src/audit-history/decorators/skip-audit.decorator'
/**
 * Provider-neutral online-session fields for a single program registration's
 * participation in ONE online session. Holds the provider's external registrant
 * id, join URL and the panelist/attendee role — the canonical "who registered"
 * record stays in hdb_program_registration. `provider` records which online
 * provider (zoom, …) issued these values.
 *
 * A registration can be pushed to several online sessions, so the key is
 * (registration_id, online_session_id) — one active row per registrant per
 * session — not a 1:1 with the registration.
 */
@Entity('hdb_program_registration_online_session')
@Index('uq_prog_reg_online_session_reg_session', ['registrationId', 'onlineSessionId'], {
  unique: true,
  where: '"deleted_at" IS NULL',
})
@Auditable()
export class ProgramRegistrationOnlineSession {
  @PrimaryGeneratedColumn('increment', { type: 'bigint' })
  id: number;

  @Column({ name: 'registration_id', type: 'bigint', nullable: false })
  registrationId: number;

  @SkipAudit()
  @ManyToOne(() => ProgramRegistration, { nullable: false })
  @JoinColumn({ name: 'registration_id' })
  registration: ProgramRegistration;

  @Column({ name: 'online_session_id', type: 'bigint', nullable: true })
  onlineSessionId: number | null;

  @SkipAudit()
  @ManyToOne(() => OnlineSession, { nullable: true })
  @JoinColumn({ name: 'online_session_id' })
  onlineSession: OnlineSession | null;

  @Column({ name: 'provider', type: 'varchar', length: 50, nullable: true })
  provider: SessionProviderType | null;

  @Column({ name: 'external_registrant_id', type: 'varchar', length: 255, nullable: true })
  externalRegistrantId: string | null;

  @Column({ name: 'join_url', type: 'text', nullable: true })
  joinUrl: string | null;

  @Column({ name: 'is_panelist', type: 'boolean', default: false })
  isPanelist: boolean;

  @Column({ name: 'registration_type', type: 'varchar', length: 50, nullable: true })
  registrationType: string | null;

  /**
   * Provisioning outcome of this (registration, online session) pair. Only
   * `REGISTERED` rows count as generated and block re-registration; `FAILED` rows
   * are durable failure records (no join link) that a later success flips back to
   * `REGISTERED`. Existing/new successful rows default to `REGISTERED`.
   */
  @Column({
    name: 'status',
    type: 'varchar',
    length: 30,
    default: OnlineSessionRegistrationStatus.REGISTERED,
  })
  status: OnlineSessionRegistrationStatus;

  @Column({ name: 'failure_reason', type: 'varchar', length: 100, nullable: true })
  failureReason: string | null;

  @Column({ name: 'failure_message', type: 'text', nullable: true })
  failureMessage: string | null;

  @Column({ name: 'attempt_count', type: 'int', default: 0 })
  attemptCount: number;

  @Column({ name: 'last_attempt_at', type: 'timestamptz', nullable: true })
  lastAttemptAt: Date | null;

  /**
   * Human toggle: is this registrant currently active for this session (holds a
   * live join link) or has an admin/RM/Shoba deactivated them. Independent of
   * `status` above — a `FAILED` row has no join link regardless of this flag.
   */
  @Column({
    name: 'activation_status',
    type: 'varchar',
    length: 20,
    default: RegistrationOnlineSessionActivationStatus.ACTIVE,
  })
  activationStatus: RegistrationOnlineSessionActivationStatus;

  @Column({ name: 'activation_changed_at', type: 'timestamptz', nullable: true })
  activationChangedAt: Date | null;

  @Column({ name: 'activation_changed_by', type: 'int', nullable: true })
  activationChangedBy: number | null;

  @Column({ name: 'activation_reason', type: 'text', nullable: true })
  activationReason: string | null;

  /**
   * Which action last changed `activationStatus` — null until any action has
   * ever been taken on this row. See `RegistrationOnlineSessionActivationSource`.
   */
  @Column({ name: 'activation_source', type: 'varchar', length: 20, nullable: true })
  activationSource: RegistrationOnlineSessionActivationSource | null;

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

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

  @DeleteDateColumn({ name: 'deleted_at', type: 'timestamptz', nullable: true, default: null })
  deletedAt: Date;

  @SkipAudit()
  @ManyToOne(() => User, { nullable: true, onDelete: 'SET NULL' })
  @JoinColumn({ name: 'created_by' })
  createdBy: User;

  @SkipAudit()
  @ManyToOne(() => User, { nullable: true, onDelete: 'SET NULL' })
  @JoinColumn({ name: 'updated_by' })
  updatedBy: User;

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