const { User } = require('../models/user');
const Subscription = require('../models/subscribers');
const tools = require('../tools/general');
const server_constants = require('../tools/server_constants');
const telegrambot = require('../telegram/telegrambot');

class AuthService {
  constructor() {
    this.failedLoginAttempts = {};
    this.MAX_FAILED_ATTEMPTS = 30;
    this.BLOCK_DURATION = 30 * 60 * 1000; // 30 minutes
  }

  /**
   * Authenticate user with username and password
   */
  async authenticate(idapp, username, password, req, browser_random) {
    try {
      console.log('STO FACENDO LOGIN...');
      // Check if user is blocked
      if (this.isUserBlocked(username)) {
        const text = `Utente bloccato. Riprova più tardi. (username=${username})`;
        console.log(text);
        return {
          error: true,
          status: 403,
          code: server_constants.RIS_CODE_ERR,
          message: text,
        };
      }

      // Find user by credentials
      const user = await User.findByCredentials(idapp, username, password);

      console.log('user', user);

      if (!user) {
        return await this._handleFailedLogin(idapp, username, req);
      }

      // Reset failed attempts on successful login
      delete this.failedLoginAttempts[username];

      // Generate tokens
      const { token, refreshToken, browser_random } = await user.generateAuthToken(req);

      // Prepare user data to send
      const userToSend = this._prepareUserData(user);

      console.log('userToSend', userToSend);

      // Check subscription
      const subsExistonDb = await this._checkSubscription(user._id, req.get('User-Agent'), browser_random);

      return {
        error: false,
        token,
        refreshToken,
        browser_random,
        user: userToSend,
        subsExistonDb,
      };
    } catch (error) {
      console.error('Error in authenticate:', error.message);
      return {
        error: true,
        status: 400,
        code: server_constants.RIS_CODE_LOGIN_ERR_GENERIC,
        message: error.message,
      };
    }
  }

  /**
   * Refresh authentication token
   */
  async refreshToken(refreshToken, req) {
    try {
      if (!refreshToken) {
        return {
          error: true,
          status: 400,
          message: 'Refresh token mancante',
        };
      }

      const user = await User.findByRefreshTokenAnyAccess(refreshToken);

      if (!user) {
        return {
          error: true,
          status: 403,
          message: 'Refresh token non valido',
        };
      }

      const { token, refreshToken: newRefreshToken, browser_random } = await user.generateAuthToken(req);

      return {
        error: false,
        token,
        refreshToken: newRefreshToken,
        browser_random,
      };
    } catch (error) {
      console.error('Error in refreshToken:', error.message);
      return {
        error: true,
        status: 500,
        message: 'Errore interno del server',
      };
    }
  }

  /**
   * Remove authentication token (logout)
   */
  async removeToken(user, token) {
    try {
      await user.removeToken(token);
      return { success: true };
    } catch (error) {
      console.error('Error in removeToken:', error.message);
      throw error;
    }
  }

  /**
   * Check if user is blocked due to too many failed attempts
   */
  isUserBlocked(username) {
    const now = Date.now();
    return this.failedLoginAttempts[username] && this.failedLoginAttempts[username] > now;
  }

  /**
   * Block user after too many failed attempts
   */
  blockUser(username) {
    this.failedLoginAttempts[username] = Date.now() + this.BLOCK_DURATION;
  }

  /**
   * Handle failed login attempt
   * @private
   */
  async _handleFailedLogin(idapp, username, req) {
    // Check database for too many wrong attempts
    const loginCheck = await User.tooManyLoginWrong(idapp, username, true);

    if (loginCheck.troppilogin) {
      const text = `Troppe richieste di Login ERRATE: ${username} [IP: ${tools.getiPAddressUser(req)}] Tentativi: ${
        loginCheck.retry_pwd
      }`;
      await telegrambot.sendMsgTelegramToTheManagers(idapp, text);
      console.log('/login', text);

      return {
        error: true,
        status: 400,
        code: server_constants.RIS_CODE_ERR,
        message: text,
      };
    }

    await tools.snooze(2000);

    // Track failed attempts in memory
    if (!this.failedLoginAttempts[username]) {
      this.failedLoginAttempts[username] = 1;
    } else {
      this.failedLoginAttempts[username]++;
    }

    const numAttempts = this.failedLoginAttempts[username];

    // Notify after multiple failed attempts
    if (numAttempts > 2) {
      const msg = `Tentativo (${numAttempts}) di Login ERRATO [${username}]\n[IP: ${tools.getiPAddressUser(req)}]`;
      tools.mylogshow(msg);
      await telegrambot.sendMsgTelegramToTheAdmin(idapp, msg, true);
      tools.writeErrorLog(msg);
    }

    // Block user after max attempts
    if (this.failedLoginAttempts[username] >= this.MAX_FAILED_ATTEMPTS) {
      this.blockUser(username);
      const text = `Troppi tentativi di accesso falliti. Utente bloccato (${username}) [IP: ${tools.getiPAddressUser(
        req
      )}]`;
      tools.mylogshow(text);
      await telegrambot.sendMsgTelegramToTheManagers(idapp, text);

      return {
        error: true,
        status: 403,
        code: server_constants.RIS_CODE_ERR,
        message: text,
      };
    }

    return {
      error: true,
      status: 401,
      code: server_constants.RIS_CODE_LOGIN_ERR,
      message: 'Credenziali non valide',
    };
  }

  /**
   * Prepare user data for response
   * @private
   */
  _prepareUserData(user) {
    const shared_consts = require('../tools/shared_nodejs');
    const userToSend = new User();

    shared_consts.fieldsUserToChange().forEach((field) => {
      userToSend[field] = user[field];
    });

    return userToSend;
  }

  /**
   * Check if subscription exists
   * @private
   */
  async _checkSubscription(userId, userAgent, browser_random) {
    try {
      const subscription = await Subscription.findOne({
        userId,
        access: 'auth',
        browser: userAgent,
        browser_random,
      }).lean();

      return !!subscription;
    } catch (error) {
      console.error('Error checking subscription:', error.message);
      return false;
    }
  }
}

module.exports = AuthService;
