/**
 * Constants for the provider-agnostic online-session lifecycle:
 * API response messages, log messages, Swagger summaries, and list defaults.
 * Error strings live in the global error registries (error-string-constants.ts
 * + i18n/error-messages.ts).
 */

import { WebinarDetails } from '../interfaces/online-details.interface';
import { RegistrationOnlineSessionActivationStatus } from '../enum/registration-online-session-activation-status.enum';
import { ProvisionRegistrationStatus } from 'src/online-session/interfaces/online-session.interface';
import { USER_TYPE_FILTER_OPTIONS } from '../utils/user-type-filter.util';

/**
 * Column descriptor for the online-session module's own admin tables. Same shape
 * as the registration module's ProgramTypeTableHeader by convention (key, label,
 * sortable, filterable, type, order) — deliberately a separate/independent
 * definition rather than a shared import, since the two tables' needs may
 * diverge over time.
 */
export interface OnlineSessionTableHeader {
  key: string;
  label: string;
  sortable: boolean;
  filterable: boolean;
  type: string;
  order: string;
}

/** One selectable choice for an OnlineSessionFilterOption: what the user sees vs. what the query param must send back. */
export interface OnlineSessionFilterChoice {
  label: string;
  value: string;
}

/** Filter descriptor for the online-session module's own admin tables — independent of the registration module's filter config, same reasoning as OnlineSessionTableHeader. */
export interface OnlineSessionFilterOption {
  key: string;
  label: string;
  type: 'select' | 'checkbox' | 'boolean' | 'string' | 'number' | 'date' | 'dropdown';
  /** Omitted for a dynamic filter whose options are fetched separately (see rmContact on eligible-registrations). */
  options?: OnlineSessionFilterChoice[];
}

/**
 * Webinar detail keys lifted into dedicated `hdb_online_session` columns; any
 * other key on WebinarDetails falls into the JSON `details` column. Used by the
 * online-session mapper.
 */
export const WEBINAR_COLUMN_KEYS: (keyof WebinarDetails)[] = [
  'provider',
  'webinarId',
  'webinarLink',
  'webinarPassword',
  'registrationLink',
  'panelistLink',
  'hostEmail',
  'startUrl',
  'status',
  'actualMeetingEndsAt',
];

/** Success messages returned in the API response envelope. */
export const ONLINE_SESSION_RESPONSE = {
  CREATED: 'Online session created',
  BULK_CREATED: 'Online sessions processed',
  SHARED_CREATED: 'Shared online sessions created',
  UPDATED: 'Online session updated',
  STATUS_UPDATED: 'Online session status updated',
  DELETED: 'Online session deleted',
  RETRIEVED: 'Online session retrieved',
  LIST_RETRIEVED: 'Online sessions retrieved',
  REGISTRATION_PROCESSED: 'Registration processed',
  BULK_REGISTRATION_STARTED: 'Bulk registration started',
  BULK_REGISTRATION_STATUS: 'Bulk registration status',
  BULK_REGISTRATION_FAILURES: 'Bulk registration failures',
  BULK_REGISTRATION_RETRY_STARTED: 'Bulk registration retry started',
  REGISTRATIONS_RETRIEVED: 'Session registrations retrieved',
  REGISTRATION_EXPORT_READY: 'Registration export ready',
  PROVISION_STATUS_RETRIEVED: 'Provisioning status retrieved',
  PROVISION_REGISTRATIONS_RETRIEVED: 'Provisioning registrations retrieved',
  ACTIVATION_UPDATED: 'Registration activation status updated',
  ELIGIBLE_COUNT_RETRIEVED: 'Eligible count retrieved',
  PROGRAM_ELIGIBLE_REGISTRATIONS_RETRIEVED: "Program's eligible registrations retrieved",
} as const;

/** Log messages emitted by the online-session orchestrator. */
export const ONLINE_SESSION_LOG = {
  CREATE_FAILED: 'Failed to create online session',
  BULK_CREATE_PARTIAL: (failed: number, total: number): string =>
    `Bulk online-session create finished with ${failed}/${total} failure(s)`,
  UPDATE_FAILED: 'Failed to update online session',
  DELETE_FAILED: 'Failed to delete online session',
  GET_BY_ID_FAILED: 'Error finding online session by id',
  LIST_FAILED: 'Error fetching online sessions',
  COMPLETED_FETCH_FAILED: 'Error fetching recently completed sessions',
  PROVIDER_OVERWRITTEN: (key: string): string =>
    `Online-session provider '${key}' is being overwritten`,
  PROVIDER_REGISTERED: (key: string): string => `Registered online-session provider: ${key}`,
  NO_PROVIDER_REGISTERED: (key: string): string =>
    `No online-session provider registered for '${key}'`,
  GENERAL_LINKS_SKIPPED_NOT_PROVISIONED: (programSessionId: number): string =>
    `Skipped general-link generation for program session ${programSessionId} — not created in Zoom (no externalId)`,
} as const;

/** Swagger operation summaries for the online-session controller. */
export const ONLINE_SESSION_SWAGGER = {
  TAG: 'online-session',
  CREATE: 'Create an online session (provider + type from body)',
  CREATE_BULK: 'Create multiple online sessions in a single request',
  CREATE_SHARED:
    'Provision ONE recurring webinar shared across several program sessions ("same link": one join link per registrant, valid for all sessions)',
  LIST: 'List online sessions',
  GET: 'Get an online session by id',
  UPDATE: 'Update an online session',
  UPDATE_STATUS: 'Update only the lifecycle status (local-only, no provider call)',
  DELETE: 'Delete an online session',
  REGISTER: 'Register/unregister/downgrade a registrant for an online session',
  BULK_REGISTER:
    'Admin: bulk-register all confirmed registrants (by programId or sessionId) as a background job',
  BULK_REGISTER_STATUS:
    'Admin: poll a bulk registration job — running counts and eligibility breakdown',
  BULK_REGISTER_FAILURES:
    "Admin: paginated, enriched per-item failure list for a bulk registration job (registrant + session details, so failures can be acted on directly)",
  BULK_REGISTER_RETRY:
    'Admin: re-run only the failed registrations of a bulk job as a fresh job (returns the new jobId)',
  PROGRAM_REGISTER_FAILURES:
    "Admin: current registration failures for a program (optionally one session), merged across the program's job chain and de-staled — what is still failing, by program/session rather than by jobId",
  PROGRAM_REGISTER_RETRY:
    'Admin: re-run the current registration failures of a program (optionally one session) as a fresh job (returns the new jobId)',
  LIST_REGISTRATIONS:
    "Admin: list a session's eligible registrants with their join URL (paginated/searchable; download=true for Excel) — excludes registrants deactivated for this specific session",
  PROVISION_STATUS:
    'Admin: per-session provisioning overview for a program (optionally one session) — total eligible, generated, failed, and yet-to-generate counts',
  PROVISION_REGISTRATIONS:
    "Admin: per-session provisioning drilldown — the eligible registrations bucketed into generated / failed / yet-to-generate (optionally filtered to one bucket)",
  SET_ACTIVATION:
    'Admin/RM/Shoba: toggle a registration active/inactive for ALL upcoming sessions of its program (past and currently-live sessions untouched) — deactivating removes their Zoom join links, reactivating re-provisions them. Rows are updated in place, never deleted.',
  ELIGIBLE_COUNT:
    "Admin: live active/inactive breakdown of one session's eligible (provisioned) registrants",
  PROGRAM_ELIGIBLE_REGISTRATIONS:
    'Admin: paginated/searchable list of a program\'s seat-allocated registrants with tableHeaders — no per-session joinUrl (that only means something scoped to one session; use the per-session registrations endpoint for that)',
} as const;

/**
 * Column descriptors for GET /online-session/eligible-registrations — returned
 * in the response so the frontend never hardcodes them. Static: this endpoint's
 * fields don't vary by caller role (the whole route is already role-gated at the
 * controller level to admin/relational_manager/shoba).
 */
export const PROGRAM_ELIGIBLE_REGISTRATIONS_TABLE_HEADERS: OnlineSessionTableHeader[] = [
  { key: 'profileUrl', label: 'Profile URL', sortable: false, filterable: false, type: 'string', order: '1' },
  { key: 'fullName', label: 'Name', sortable: true, filterable: true, type: 'string', order: '2' },
  { key: 'gender', label: 'Gender', sortable: false, filterable: true, type: 'string', order: '3' },
  // Derived from dob at read time, not a plain column — not sortable.
  { key: 'age', label: 'Age', sortable: false, filterable: true, type: 'number', order: '3A' },
  { key: 'city', label: 'City', sortable: true, filterable: false, type: 'string', order: '3B' },
  { key: 'mobile', label: 'Contact no.', sortable: false, filterable: false, type: 'string', order: '4' },
  { key: 'email', label: 'Email', sortable: false, filterable: false, type: 'string', order: '5' },
  { key: 'rmContact', label: 'RM', sortable: false, filterable: true, type: 'string', order: '6' },
  { key: 'registrationMode', label: 'Registration Mode', sortable: false, filterable: true, type: 'string', order: '7A' },
  // Always true for every row this endpoint returns (it's the base eligibility criterion) — not a meaningful filter.
  // { key: 'seatAllocated', label: 'Seat Allocated', sortable: false, filterable: false, type: 'boolean', order: '8' },
  { key: 'activationStatus', label: 'Activation Status', sortable: false, filterable: true, type: 'string', order: '9' },
  { key: 'paymentStatus', label: 'Payment Status', sortable: false, filterable: true, type: 'string', order: '10' },
    { key: 'registrationSeqNumber', label: 'Seq Number', sortable: true, filterable: false, type: 'string', order: '11' },
  { key: 'attendedSessions', label: 'Attendance Status', sortable: false, filterable: false, type: 'string', order: '12' },
];

/**
 * Column descriptors for GET /online-session/provision-status/:sessionId/registrations —
 * one column per {@link ProvisionRegistrationRow} field, returned in the response so the
 * frontend never hardcodes them. `status` doubles as the filter this table's own KPI tiles
 * drive (see `ProvisionKpiTile.filter`) — clicking a tile re-issues this same list with
 * `?status=<filter>`.
 */
export const PROVISION_REGISTRATIONS_TABLE_HEADERS: OnlineSessionTableHeader[] = [
  // { key: 'registrationId', label: 'Registration Id', sortable: false, filterable: false, type: 'number', order: '1' },
  // { key: 'registrationSeqNumber', label: 'Seq Number', sortable: false, filterable: false, type: 'string', order: '2' },
  { key: 'fullName', label: 'Name', sortable: false, filterable: true, type: 'string', order: '3' },
  { key: 'email', label: 'Email', sortable: false, filterable: false, type: 'string', order: '4' },
  { key: 'mobile', label: 'Contact no.', sortable: false, filterable: false, type: 'string', order: '5' },
  { key: 'status', label: 'Status', sortable: false, filterable: true, type: 'string', order: '6' },
  { key: 'joinUrl', label: 'Join URL', sortable: false, filterable: false, type: 'string', order: '7' },
  { key: 'activationStatus', label: 'Activation Status', sortable: false, filterable: true, type: 'string', order: '8' },
  { key: 'reason', label: 'Failure Reason', sortable: false, filterable: false, type: 'string', order: '9' },
  { key: 'message', label: 'Failure Message', sortable: false, filterable: false, type: 'string', order: '10' },
];

/** Only populated on a 'failed' row (see `getSessionProvisionRegistrations`) — meaningless on any other bucket's rows. */
const PROVISION_REGISTRATIONS_FAILURE_HEADER_KEYS = ['reason', 'message'];

/**
 * `PROVISION_REGISTRATIONS_TABLE_HEADERS`, minus the Reason/Message columns when the caller has
 * filtered to a bucket where those are always empty ('generated' / 'pending' / 'generalLink').
 * Kept for the unfiltered ("all buckets") view and the 'failed' filter itself, where they're the
 * whole point of the column.
 */
export function getProvisionRegistrationsTableHeaders(
  status?: ProvisionRegistrationStatus,
): OnlineSessionTableHeader[] {
  if (status && status !== 'failed') {
    return PROVISION_REGISTRATIONS_TABLE_HEADERS.filter(
      (header) => !PROVISION_REGISTRATIONS_FAILURE_HEADER_KEYS.includes(header.key),
    );
  }
  return PROVISION_REGISTRATIONS_TABLE_HEADERS;
}

/**
 * Filter options for GET /online-session/eligible-registrations — the static
 * ones (everything but rmContact, which depends on which RMs actually have
 * registrants in the given program and is fetched separately via
 * getProgramEligibleRmContacts).
 *
 * gender/registrationMode/age/paymentMode/paymentStatus deliberately mirror the
 * SAME label/value pairs the main registration module's filter config uses
 * (filter-hierarchy.config.ts's sideFilterSets.baseSets) — same brackets/codes
 * admins already expect — with one deviation: gender's values are lowercase
 * ("male"/"female") rather than that config's capitalized "Male"/"Female", so
 * the filter application does a case-insensitive match against the column.
 */
export const PROGRAM_ELIGIBLE_REGISTRATIONS_STATIC_FILTERS: OnlineSessionFilterOption[] = [
  {
    key: 'gender',
    label: 'Gender',
    type: 'select',
    options: [
      { label: 'Male', value: 'Male' },
      { label: 'Female', value: 'Female' },
    ],
  },
  {
    key: 'registrationMode',
    label: 'Registration Mode',
    type: 'select',
    options: [
      { label: 'Self', value: 'self' },
      { label: 'Other', value: 'other' },
    ],
  },
  {
    key: 'age',
    label: 'Age',
    type: 'select',
    options: [
      { label: '<=20 years', value: '0-20' },
      { label: '21 - 30 years', value: '21-30' },
      { label: '31 - 50 years', value: '31-50' },
      { label: '51 - 65 years', value: '51-65' },
      { label: '> 65 years', value: '>65' },
    ],
  },
  {
    key: 'activationStatus',
    label: 'Activation Status',
    type: 'select',
    options: [
      { label: 'Active', value: RegistrationOnlineSessionActivationStatus.ACTIVE },
      { label: 'Inactive', value: RegistrationOnlineSessionActivationStatus.INACTIVE },
    ],
  },
  {
    key: 'paymentMode',
    label: 'Payment Mode',
    type: 'select',
    options: [
      { label: 'Online', value: 'online' },
      { label: 'Offline', value: 'offline' },
    ],
  },
  {
    key: 'paymentStatus',
    label: 'Payment Status',
    type: 'select',
    options: [
      { label: 'Completed', value: 'payment_completed' },
      { label: 'Pending', value: 'payment_pending' },
      { label: 'Failed', value: 'failed' },
      { label: 'No payment', value: 'no_payment' },
    ],
  },
  // The registrant's own user-account type. `checkbox` rather than `select` because the two types
  // aren't mutually exclusive — selecting both means "Org or Seeker" (a plain IN), see
  // resolveUserTypeFilter.
  {
    key: 'userType',
    label: 'User Type',
    type: 'checkbox',
    options: [...USER_TYPE_FILTER_OPTIONS],
  },
];

/**
 * Column descriptors for GET /online-session — mirrors the screenshot-matched
 * admin Sessions table (session/time/duration + the Registered/Attended/Absent
 * + duration-bucket attendance columns), returned in the response so the
 * frontend never hardcodes them.
 */
export const ONLINE_SESSION_LIST_TABLE_HEADERS: OnlineSessionTableHeader[] = [
  { key: 'name', label: 'Session', sortable: false, filterable: false, type: 'string', order: '1' },
  { key: 'startsAt', label: 'Date & Time', sortable: true, filterable: false, type: 'string', order: '2' },
  { key: 'duration', label: 'Duration', sortable: false, filterable: false, type: 'number', order: '3' },
  { key: 'registered', label: 'Attendees', sortable: false, filterable: false, type: 'number', order: '4' },
  { key: 'attended', label: 'Present', sortable: false, filterable: false, type: 'number', order: '5' },
  { key: 'absent', label: 'Absent', sortable: false, filterable: false, type: 'number', order: '6' },
  { key: 'under60', label: '< 60 min', sortable: false, filterable: false, type: 'number', order: '7' },
  { key: 'from60to90', label: '60-90 min', sortable: false, filterable: false, type: 'number', order: '8' },
  { key: 'from90to120', label: '90-120 min', sortable: false, filterable: false, type: 'number', order: '9' },
  { key: 'completed', label: 'Completed', sortable: false, filterable: true, type: 'boolean', order: '10' },
];

/** Defaults for the list endpoint. */
export const ONLINE_SESSION_LIST_DEFAULTS = {
  LIMIT: 10,
  OFFSET: 0,
} as const;
