import { logger } from '@goodgo/logger';
import { PrismaClient } from '@prisma/client';

import { getPrismaClient } from '../../config/database.config';

/**
 * EN: Account Lockout Service for failed login attempt protection
 * VI: Service Account Lockout để bảo vệ chống brute force login
 */
export class AccountLockoutService {
  private prisma: PrismaClient;
  private readonly maxAttempts = 5; // Maximum failed attempts before lockout
  private readonly lockoutDurationMinutes = 15; // Lockout duration in minutes

  constructor() {
    this.prisma = getPrismaClient();
  }

  /**
   * EN: Record a failed login attempt
   * VI: Ghi nhận một lần đăng nhập thất bại
   */
  async recordFailedAttempt(userId: string): Promise<void> {
    try {
      const user = await this.prisma.user.findUnique({
        where: { id: userId },
        select: { failedLoginAttempts: true, lockedUntil: true },
      });

      if (!user) {
        return;
      }

      const newAttempts = user.failedLoginAttempts + 1;
      const shouldLock = newAttempts >= this.maxAttempts;

      if (shouldLock) {
        // Lock the account
        const lockedUntil = new Date();
        lockedUntil.setMinutes(lockedUntil.getMinutes() + this.lockoutDurationMinutes);

        await this.prisma.user.update({
          where: { id: userId },
          data: {
            failedLoginAttempts: newAttempts,
            lockedUntil,
          },
        });

        logger.warn('Account locked due to too many failed attempts', {
          userId,
          attempts: newAttempts,
          lockedUntil,
        });
      } else {
        // Just increment the counter
        await this.prisma.user.update({
          where: { id: userId },
          data: {
            failedLoginAttempts: newAttempts,
          },
        });
      }
    } catch (error) {
      logger.error('Failed to record login attempt', { userId, error });
    }
  }

  /**
   * EN: Clear failed login attempts (on successful login)
   * VI: Xóa các lần đăng nhập thất bại (khi đăng nhập thành công)
   */
  async clearFailedAttempts(userId: string): Promise<void> {
    try {
      await this.prisma.user.update({
        where: { id: userId },
        data: {
          failedLoginAttempts: 0,
          lockedUntil: null,
        },
      });

      logger.debug('Failed login attempts cleared', { userId });
    } catch (error) {
      logger.error('Failed to clear login attempts', { userId, error });
    }
  }

  /**
   * EN: Check if account is locked
   * VI: Kiểm tra tài khoản có bị khóa không
   */
  async isAccountLocked(userId: string): Promise<boolean> {
    try {
      const user = await this.prisma.user.findUnique({
        where: { id: userId },
        select: { lockedUntil: true },
      });

      if (!user || !user.lockedUntil) {
        return false;
      }

      const now = new Date();
      const isLocked = user.lockedUntil > now;

      if (!isLocked) {
        // Lockout period has expired, clear it
        await this.clearFailedAttempts(userId);
      }

      return isLocked;
    } catch (error) {
      logger.error('Failed to check account lock status', { userId, error });
      return false; // Fail open for account lock checks
    }
  }

  /**
   * EN: Get lockout status and remaining time
   * VI: Lấy trạng thái khóa và thời gian còn lại
   */
  async getLockoutStatus(userId: string): Promise<{
    isLocked: boolean;
    remainingMinutes?: number;
  }> {
    try {
      const user = await this.prisma.user.findUnique({
        where: { id: userId },
        select: { lockedUntil: true },
      });

      if (!user || !user.lockedUntil) {
        return { isLocked: false };
      }

      const now = new Date();
      const isLocked = user.lockedUntil > now;

      if (!isLocked) {
        // Lockout expired, clear it
        await this.clearFailedAttempts(userId);
        return { isLocked: false };
      }

      const remainingMs = user.lockedUntil.getTime() - now.getTime();
      const remainingMinutes = Math.ceil(remainingMs / (1000 * 60));

      return {
        isLocked: true,
        remainingMinutes,
      };
    } catch (error) {
      logger.error('Failed to get lockout status', { userId, error });
      return { isLocked: false };
    }
  }

  /**
   * EN: Get lockout configuration
   * VI: Lấy cấu hình khóa tài khoản
   */
  getLockoutConfig(): {
    maxAttempts: number;
    lockoutDurationMinutes: number;
  } {
    return {
      maxAttempts: this.maxAttempts,
      lockoutDurationMinutes: this.lockoutDurationMinutes,
    };
  }

  /**
   * EN: Manually unlock an account (admin function)
   * VI: Mở khóa tài khoản thủ công (chức năng admin)
   */
  async unlockAccount(userId: string): Promise<void> {
    try {
      await this.clearFailedAttempts(userId);
      logger.info('Account manually unlocked', { userId });
    } catch (error) {
      logger.error('Failed to unlock account', { userId, error });
      throw error;
    }
  }
}

export const accountLockoutService = new AccountLockoutService();