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

import { ports } from './ports';
import { clients } from './clients';

/**
 * Portal users - one per client account that's been invited to the client
 * portal. Separate from the CRM `users` table (managed by better-auth) so the
 * authentication realms stay isolated.
 *
 * Created by an admin from the client detail page; the admin's invite mails
 * an activation token that lets the client set their own password.
 */
export const portalUsers = pgTable(
  'portal_users',
  {
    id: text('id')
      .primaryKey()
      .$defaultFn(() => crypto.randomUUID()),
    portId: text('port_id')
      .notNull()
      .references(() => ports.id),
    clientId: text('client_id')
      .notNull()
      .references(() => clients.id, { onDelete: 'cascade' }),
    email: text('email').notNull(),
    /**
     * scrypt-hashed password. Format: `salt:keyHex` (both base64url). Null
     * until the user activates their account.
     */
    passwordHash: text('password_hash'),
    /**
     * Watermark for JWT-session revocation on password change. Any
     * `verifyPortalToken` call where the JWT's `iat` is older than this
     * value rejects the token even if it's otherwise valid. Updated on
     * `resetPassword`, `activateAccount`, and `changePortalPassword` so
     * a stolen cookie stops working after the legitimate owner does the
     * forgot-password / change-password dance. auth-flow-auditor C1.
     */
    passwordChangedAt: timestamp('password_changed_at', { withTimezone: true })
      .notNull()
      .defaultNow(),
    name: text('name'),
    isActive: boolean('is_active').notNull().default(true),
    lastLoginAt: timestamp('last_login_at', { withTimezone: true }),
    createdBy: text('created_by').notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    uniqueIndex('idx_portal_users_email_unique').on(table.email),
    index('idx_portal_users_client').on(table.clientId),
    index('idx_portal_users_port').on(table.portId),
  ],
);

/**
 * Single-use tokens for portal-account activation and password reset.
 *
 * `tokenHash` is a SHA-256 hash of the raw token sent in the email. Lookups
 * happen by hash so a DB compromise never leaks active tokens.
 */
export const portalAuthTokens = pgTable(
  'portal_auth_tokens',
  {
    id: text('id')
      .primaryKey()
      .$defaultFn(() => crypto.randomUUID()),
    portalUserId: text('portal_user_id')
      .notNull()
      .references(() => portalUsers.id, { onDelete: 'cascade' }),
    tokenHash: text('token_hash').notNull(),
    type: text('type').notNull(), // 'activation' | 'reset'
    expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
    usedAt: timestamp('used_at', { withTimezone: true }),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    uniqueIndex('idx_portal_tokens_hash_unique').on(table.tokenHash),
    index('idx_portal_tokens_user').on(table.portalUserId),
  ],
);

export type PortalUser = typeof portalUsers.$inferSelect;
export type NewPortalUser = typeof portalUsers.$inferInsert;
export type PortalAuthToken = typeof portalAuthTokens.$inferSelect;
export type NewPortalAuthToken = typeof portalAuthTokens.$inferInsert;
