import { pgTable, serial, integer, text, timestamp, index } from 'drizzle-orm/pg-core';
import { users } from '../auth/schema';

// Per-device credentials for CalDAV / CardDAV clients — DAVx5, iOS, macOS, Thunderbird.
//
// A new credential type is unavoidable and NextCloud solved it the same way for the same reason: a DAV
// client cannot log into Officer. It speaks HTTP Basic on every request and has nowhere to put a 30-day
// JWT, no way to refresh one, and no way to answer a passkey challenge. Without this table the only
// credential a phone could carry is the account password itself — which then lives in that phone's
// account manager in recoverable form, and in whatever backs the phone up.
//
// So: one password per device, revocable per device, hashed with argon2 like the account password and
// SHOWN EXACTLY ONCE at creation. Nothing reads the plaintext back, because nothing stores it.
//
// SCOPE IS LOAD-BEARING. These are accepted ONLY by the /dav mount. `userMiddleware` must never look at
// this table — an app password is not a session, and a device that syncs a calendar has no business
// reaching the wallet or the vault.
//
// `revokedAt` rather than a delete, so a revoked credential stays visible in the UI ("this phone had
// access until Tuesday") instead of silently vanishing. `lastUsedAt` is what makes a stale device
// noticeable at all.
export const davAppPasswords = pgTable(
  'dav_app_passwords',
  {
    id: serial('id').primaryKey(),
    userId: integer('user_id')
      .notNull()
      .references(() => users.id, { onDelete: 'cascade' }),
    /** What the owner calls the device — "Pixel 9", "iPad". The only way to tell two rows apart in the UI. */
    label: text('label').notNull(),
    /** argon2 hash. Deliberately not unique: two devices could in principle collide and it would not matter. */
    passwordHash: text('password_hash').notNull(),
    /**
     * First 8 chars of the generated secret, stored in the clear on purpose. It is not enough to
     * authenticate with, and it is the only way for the owner to match a row in this list against the
     * password saved on a device they are looking at.
     */
    hint: text('hint').notNull(),
    lastUsedAt: timestamp('last_used_at', { withTimezone: true }),
    revokedAt: timestamp('revoked_at', { withTimezone: true }),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  // Every DAV request authenticates, and a phone polls often. This index is the difference between that
  // being free and it being a sequential scan on every PROPFIND.
  (t) => [index('idx_dav_app_passwords_user').on(t.userId)],
);
