import type pg from 'pg';
import type { PasswordResetToken } from '../domain/password-reset.js';
import type { PasswordResetTokenRepository } from '../domain/ports.js';

type Row = {
  id: string;
  user_id: string;
  token_hash: string;
  expires_at: Date;
  used_at: Date | null;
  created_at: Date;
};

function toDomain(row: Row): PasswordResetToken {
  return {
    id: row.id,
    userId: row.user_id,
    tokenHash: row.token_hash,
    expiresAt: row.expires_at,
    usedAt: row.used_at,
    createdAt: row.created_at,
  };
}

export class PgPasswordResetTokenRepository implements PasswordResetTokenRepository {
  constructor(private readonly pool: pg.Pool) {}

  async invalidateAllForUser(userId: string): Promise<void> {
    await this.pool.query(
      `UPDATE identity_password_reset_tokens
       SET used_at = now()
       WHERE user_id = $1 AND used_at IS NULL`,
      [userId],
    );
  }

  async create(input: {
    userId: string;
    tokenHash: string;
    expiresAt: Date;
    requestIp?: string;
    requestUserAgent?: string;
  }): Promise<PasswordResetToken> {
    const result = await this.pool.query<Row>(
      `INSERT INTO identity_password_reset_tokens
        (user_id, token_hash, expires_at, request_ip, request_user_agent)
       VALUES ($1, $2, $3, $4, $5)
       RETURNING *`,
      [input.userId, input.tokenHash, input.expiresAt, input.requestIp ?? null, input.requestUserAgent ?? null],
    );
    const row = result.rows[0];
    if (!row) throw new Error('password reset token INSERT returned no row');
    return toDomain(row);
  }

  async findByTokenHash(tokenHash: string): Promise<PasswordResetToken | undefined> {
    const result = await this.pool.query<Row>(
      `SELECT * FROM identity_password_reset_tokens WHERE token_hash = $1`,
      [tokenHash],
    );
    const row = result.rows[0];
    return row ? toDomain(row) : undefined;
  }

  async markUsed(id: string): Promise<void> {
    await this.pool.query(
      `UPDATE identity_password_reset_tokens SET used_at = now() WHERE id = $1 AND used_at IS NULL`,
      [id],
    );
  }
}