import { pgTable, serial, text, boolean, timestamp, uniqueIndex } from 'drizzle-orm/pg-core';

// Which plugins are installed on this machine, and whether they should be mounted.
//
// ── Why a row is needed at all, when the code is already on disk ──
//
// Plugins live in the repository (`platform/plugins/<app-name>/`), so PRESENCE is not installation. A
// developer working on a plugin has the directory there and has not installed anything; a plugin that
// ships in a checkout should not mount itself because someone cloned it. The directory answers "what
// could run here", this table answers "what does".
//
// ── Separate from `sidecar_installs`, deliberately ──
//
// That table belongs to the app store's model, where an install means provisioning a container or
// pointing at a remote instance, and it carries `mode`, `compose_dir` and `completed_steps` to say so.
// A plugin install has none of those: put the code there, push its schema, start its sidecar, mount its
// routes. Reusing the table would have meant a `mode` that lies about every plugin. The two models
// coexist until the app store is rebuilt on this one.
//
// ── No userId, for the same reason as `sidecar_installs` ──
//
//   installed   server-level, owner-only   — this row
//   permitted   per role                   — role_capabilities
//   configured  per user                   — the plugin's own tables
//
// ── `enabled` is not `installed` ──
//
// Installed means the schema is pushed and the code is ready. Enabled means it should be mounted and its
// sidecar running. Disabling is the reversible middle: routes come down, the process stops, and every
// table and row it owns survives untouched. Uninstalling drops the row and unmounts, and still does not
// delete data — dropping a plugin's tables is a separate, deliberate act with the cost shown.
export const pluginInstalls = pgTable(
  'plugin_installs',
  {
    id: serial('id').primaryKey(),
    /**
     * The plugin's app name — its directory, its route segment and its table prefix, all the same string.
     * Text rather than an enum: adding a plugin must never be a schema change.
     */
    appName: text('app_name').notNull(),
    /**
     * The manifest version at the moment it was installed.
     *
     * Kept so an upgrade has something to compare against, and so "installed" can be told from "installed,
     * then the code on disk moved underneath it" — which is the normal state on a developer's machine and
     * a thing worth being able to see rather than infer.
     */
    version: text('version').notNull(),
    enabled: boolean('enabled').notNull().default(true),
    installedAt: timestamp('installed_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => [
    // One row per plugin, machine-wide. uniqueIndex rather than unique() — see databases/CLAUDE.md on
    // drizzle-kit re-creating named composite constraints on every push.
    uniqueIndex('uq_plugin_installs_app_name').on(t.appName),
  ],
);
