import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  Index,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

/**
 * One row per seeker per session — the reconciled per-person snapshot backing
 * the admin screen's seeker table (Full Name, Email, Phone, Joined At, No. of
 * Devices, Drop-offs/Rejoined, Last Drop-off/Rejoined, Attendance). Standalone
 * table; upserted (update-in-place) by the resource-type provider's
 * `reconcile()`. RM/Coordinator attendance marks live in
 * `program_user_attendance.attendance_events` (the one canonical attendance
 * table — `AttendanceSourceEnum.MANUAL_RM`/`MANUAL_COORDINATOR`), not here;
 * `ZoomAnalyticsFacadeService.markAttendance()` writes there via
 * `OnlineAttendanceService`, and the seeker table reads them back via
 * `OnlineAttendanceService.getManualMarksBySession()`, keyed by registrationId.
 */
@Entity('zoom_analytics_attendee_summary')
// One real email can back several sibling registrations (proxy/child regs, see
// buildZoomRegistrantEmail) — registrationId, not email, is the true per-seeker key.
@Index('uq_zoom_analytics_attendee_summary_session_registration', ['sessionId', 'registrationId'], {
  unique: true,
})
// General attendees (joined via the shared/common link) all carry registrationId NULL, and Postgres
// treats every NULL in a unique index as distinct — so this partial index is what actually keeps one
// row per general attendee per session, keyed by email instead.
@Index('uq_zoom_analytics_attendee_summary_session_email_general', ['sessionId', 'email'], {
  unique: true,
  where: '"registration_id" IS NULL',
})
export class ZoomAnalyticsAttendeeSummary {
  @PrimaryGeneratedColumn('increment', { type: 'bigint' })
  id: number;

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

  @Index()
  @Column({ name: 'session_id', type: 'int' })
  sessionId: number;

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

  /** Links back to the platform's actual User record, resolved via the roster (not just the Zoom-reported email). */
  @Column({ name: 'user_id', type: 'int', nullable: true })
  userId: number | null;

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

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

  /** The most recent display name Zoom reported for this seeker joining — distinct from fullName (our own registration record), never overwrites it. */
  @Column({ name: 'zoom_display_name', type: 'varchar', length: 255, nullable: true })
  zoomDisplayName: string | null;

  @Column({ name: 'email', type: 'varchar', length: 255 })
  email: string;

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

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

  /**
   * Best-known count of distinct devices/connections this seeker used to join — the larger of distinct
   * `zoom_participant_id`s seen (only populated for participants logged into a Zoom account) and the
   * peak number of concurrently-open connections inferred from JOIN/LEFT interleaving alone (needs no
   * id: two JOINs with no LEFT between them proves two connections were open). 0 if they never joined.
   */
  @Column({ name: 'no_of_devices', type: 'int', nullable: true })
  noOfDevices: number | null;

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

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

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

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

  /** Total seconds present from the session's actual start time onward — time present before the session started is excluded and tracked separately in preSessionDurationSeconds. */
  @Column({ name: 'duration_seconds', type: 'int', default: 0 })
  durationSeconds: number;

  /** Seconds this seeker was present before the session's actual start time (e.g. joined early/waiting room) — not counted in durationSeconds. */
  @Column({ name: 'pre_session_duration_seconds', type: 'int', default: 0 })
  preSessionDurationSeconds: number;

  /** Zoom-derived, reconciliation-only — never manually set (read-only on the admin screen). */
  @Column({ name: 'is_system_attended', type: 'boolean', default: false })
  isSystemAttended: boolean;

  @Column({ name: 'reconciled_at', type: 'timestamptz', nullable: true })
  reconciledAt: Date | 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;

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