/**
 * PostgreSQL SessionRepository. Stores token hashes only.
 * Validity (not expired, not revoked) is enforced in the SQL itself.
 */
import type pg from 'pg';
import type { SessionRepository } from '../domain/ports.js';
import type { Session } from '../domain/session.js';

interface SessionRow {
  id: string;
  user_id: string;
  created_at: Date;
  expires_at: Date;
  revoked_at: Date | null;
}

export class PgSessionRepository implements SessionRepository {
  constructor(private readonly pool: pg.Pool) {}

  async create(userId: string, tokenHash: string, expiresAt: Date): Promise<Session> {
    const result = await this.pool.query<SessionRow>(
      `INSERT INTO identity_sessions (user_id, token_hash, expires_at)
       VALUES ($1, $2, $3)
       RETURNING id, user_id, created_at, expires_at, revoked_at`,
      [userId, tokenHash, expiresAt],
    );
    const row = result.rows[0];
    if (!row) {
      throw new Error('identity_sessions INSERT returned no row');
    }
    return toSession(row);
  }

  async revokeByTokenHash(tokenHash: string): Promise<boolean> {
    const result = await this.pool.query(
      `UPDATE identity_sessions
       SET revoked_at = now()
       WHERE token_hash = $1 AND revoked_at IS NULL AND expires_at > now()`,
      [tokenHash],
    );
    return (result.rowCount ?? 0) > 0;
  }
}

function toSession(row: SessionRow): Session {
  return {
    id: row.id,
    userId: row.user_id,
    createdAt: row.created_at,
    expiresAt: row.expires_at,
    revokedAt: row.revoked_at,
  };
}
