import { Op } from 'sequelize';
import db from '@/db/models';
import type { AuthRefreshTokens } from '@/db/models/auth_refresh_tokens';
import type { DbApiOptions } from '@/db/api/types';

interface CreateData {
  userId: string;
  organizationId?: string | null;
  tokenHash: string;
  familyId: string;
  previousTokenId?: string | null;
  userAgent?: string | null;
  ipAddress?: string | null;
  expiresAt: Date;
}

class AuthRefreshTokensDBApi {
  static async create(
    data: CreateData,
    options: DbApiOptions = {},
  ): Promise<AuthRefreshTokens> {
    return db.auth_refresh_tokens.create(
      {
        userId: data.userId,
        organizationId: data.organizationId || null,
        tokenHash: data.tokenHash,
        familyId: data.familyId,
        previousTokenId: data.previousTokenId || null,
        userAgent: data.userAgent || null,
        ipAddress: data.ipAddress || null,
        expiresAt: data.expiresAt,
        revokedAt: null,
        replacedByTokenId: null,
      },
      { transaction: options.transaction },
    );
  }

  static async findByHash(
    tokenHash: string,
    options: DbApiOptions = {},
  ): Promise<AuthRefreshTokens | null> {
    return db.auth_refresh_tokens.findOne({
      where: { tokenHash },
      transaction: options.transaction,
    });
  }

  static async revoke(
    id: string,
    replacedByTokenId: string | null,
    options: DbApiOptions = {},
  ): Promise<[affectedCount: number]> {
    return db.auth_refresh_tokens.update(
      {
        revokedAt: new Date(),
        replacedByTokenId: replacedByTokenId || null,
      },
      {
        where: { id },
        transaction: options.transaction,
      },
    );
  }

  static async revokeFamily(
    familyId: string,
    options: DbApiOptions = {},
  ): Promise<[affectedCount: number]> {
    return db.auth_refresh_tokens.update(
      {
        revokedAt: new Date(),
      },
      {
        where: {
          familyId,
          revokedAt: null,
        },
        transaction: options.transaction,
      },
    );
  }

  /**
   * Physically deletes refresh-token rows that expired before `cutoff`. Used by
   * the maintenance job; a row past `expiresAt` can no longer be presented, so
   * removing it (revoked or not) is safe once the retention window has passed.
   * Returns the number of rows deleted.
   */
  static async deleteExpiredBefore(
    cutoff: Date,
    options: DbApiOptions = {},
  ): Promise<number> {
    return db.auth_refresh_tokens.destroy({
      where: { expiresAt: { [Op.lt]: cutoff } },
      transaction: options.transaction,
    });
  }
}

export default AuthRefreshTokensDBApi;
