/**
 * Learn resources — shared videos, in two kinds of track.
 *
 * The table is ordinary. One column pair on it is not, and it is the reason
 * this file carries a comment at all:
 *
 * **`visibility = 'code'` is only legal on the platform track**, and that is a
 * CHECK constraint rather than a convention. A resource marked `code` is
 * readable by someone holding the share code, who has no account, no principal
 * and no capability of any kind. Concept material about how we source and
 * price capacity must never enter that set. The API write path refuses it too,
 * but a constraint is what makes it true of rows that arrive any other way —
 * a seed, a repair script, a psql session at midnight.
 *
 * **No raw URL is ever framed.** `url` is the canonical share link, kept for a
 * human to click and for provenance; `provider` and `external_id` are what the
 * embed is rebuilt from, through the allowlist in `@pig/core`. The read paths
 * deliberately do not select `url` at all, so a poisoned value in that column
 * cannot reach an `iframe src` even by accident.
 *
 * The unique key on (track, provider, external_id) is load-bearing for the
 * seed: `onConflictDoNothing()` is a silent no-op without a constraint to
 * conflict on, and it has already duplicated seed data twice in this codebase.
 */
import { sql } from 'drizzle-orm';
import {
  check,
  index,
  integer,
  pgTable,
  text,
  timestamp,
  unique,
  uuid,
} from 'drizzle-orm/pg-core';
import {
  LEARN_CODE_TRACK,
  LEARN_PROVIDERS,
  LEARN_TRACKS,
  LEARN_VISIBILITIES,
} from '@pig/core';
import { users } from './identity';

/**
 * Render a value set as a SQL `IN` list from the ontology constant.
 *
 * Typing the values into the migration by hand is what lets the database and
 * the application disagree about the vocabulary; deriving them means removing
 * a value stops validating rather than silently persisting. The values are
 * compile-time literal constants from `@pig/core`, never input.
 */
const inList = (values: readonly string[]) =>
  sql.raw(values.map((value) => `'${value}'`).join(', '));

export const learnResources = pgTable(
  'learn_resources',
  {
    id: uuid('id').primaryKey().defaultRandom(),

    track: text('track', { enum: LEARN_TRACKS }).notNull(),
    title: text('title').notNull(),
    summary: text('summary'),

    /** The canonical share link. Shown to a human, never used as a frame src. */
    url: text('url').notNull(),
    /** Resolved from the host by the allowlist — never supplied by a client. */
    provider: text('provider', { enum: LEARN_PROVIDERS }).notNull(),
    externalId: text('external_id').notNull(),

    visibility: text('visibility', { enum: LEARN_VISIBILITIES }).notNull().default('members'),

    durationSeconds: integer('duration_seconds'),
    /** Ascending. Ties break on published_at, so a default is fine. */
    sortOrder: integer('sort_order').notNull().default(100),
    publishedAt: timestamp('published_at', { withTimezone: true }).notNull().defaultNow(),

    addedByUserId: uuid('added_by_user_id').references(() => users.id, {
      onDelete: 'set null',
    }),

    /**
     * Archive rather than delete, as everywhere else in PIG: a video pulled
     * from the curriculum is still the answer to "what did onboarding say in
     * March?", and the activity log references it.
     */
    archivedAt: timestamp('archived_at', { withTimezone: true }),

    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    check('learn_resources_track_check', sql`${t.track} IN (${inList(LEARN_TRACKS)})`),
    check(
      'learn_resources_visibility_check',
      sql`${t.visibility} IN (${inList(LEARN_VISIBILITIES)})`,
    ),
    check('learn_resources_provider_check', sql`${t.provider} IN (${inList(LEARN_PROVIDERS)})`),
    /**
     * THE constraint. Written as an implication rather than an equality so it
     * reads as the rule it encodes: code-visible implies platform track.
     */
    check(
      'learn_resources_code_is_platform_only_check',
      sql`${t.visibility} <> 'code' OR ${t.track} = ${sql.raw(`'${LEARN_CODE_TRACK}'`)}`,
    ),
    check('learn_resources_duration_check', sql`${t.durationSeconds} IS NULL OR ${t.durationSeconds} > 0`),

    unique('learn_resources_track_provider_external_key').on(t.track, t.provider, t.externalId),
    /** Both list queries are "one track, in order". */
    index('learn_resources_track_order_idx').on(t.track, t.sortOrder),
    /** The public route filters on this pair and nothing else. */
    index('learn_resources_visibility_idx').on(t.visibility, t.track),
  ],
);

export type LearnResource = typeof learnResources.$inferSelect;
export type NewLearnResource = typeof learnResources.$inferInsert;
