const bcrypt = require('bcrypt');
const { Admin, LoginHistory } = require('../models');
const { generateToken, generateRefreshToken, verifyToken } = require('../utils/jwt');
const logger = require('../config/logger');

/**
 * Admin Authentication Service
 * Handles admin login and authentication logic
 */

/**
 * Authenticate admin and generate token
 * @param {string} username - Admin username
 * @param {string} password - Admin password
 * @param {Object} loginInfo - Login metadata (IP, user agent, device info)
 * @returns {Object} Admin data and token
 */
const loginAdmin = async (username, password, loginInfo = {}) => {
  try {
    // Find admin by username
    const admin = await Admin.findOne({
      where: { username },
    });

    if (!admin) {
      throw new Error('Invalid username or password');
    }

    // Check if admin is active
    if (admin.status === 'inactive') {
      throw new Error('Admin account is inactive');
    }

    // Verify password
    const isPasswordValid = await bcrypt.compare(password, admin.password);
    
    if (!isPasswordValid) {
      throw new Error('Invalid username or password');
    }

    // Generate JWT token and refresh token
    const tokenPayload = {
      userId: admin.id,
      type: 'admin',
      role: admin.role,
    };
    
    const token = generateToken(tokenPayload);
    const refreshToken = generateRefreshToken(tokenPayload);

    // Update last login time
    await admin.update({
      lastLoginAt: new Date(),
    });

    // Record login history
    await LoginHistory.create({
      userId: admin.id,
      userType: 'admin',
      ipAddress: loginInfo.ipAddress,
      userAgent: loginInfo.userAgent,
      deviceInfo: loginInfo.deviceInfo,
      loginAt: new Date(),
    });

    logger.info(`Admin login successful: ${admin.username} (${admin.id})`);

    // Return admin data (excluding password)
    return {
      admin: {
        id: admin.id,
        username: admin.username,
        email: admin.email,
        role: admin.role,
        status: admin.status,
        lastLoginAt: admin.lastLoginAt,
      },
      token,
      refreshToken,
    };
  } catch (error) {
    logger.error('Admin login error:', error);
    throw error;
  }
};

/**
 * Refresh admin access token
 * @param {string} refreshToken - Refresh token
 * @returns {Object} New tokens
 */
const refreshAdminToken = async (refreshToken) => {
  try {
    // Verify refresh token
    const decoded = verifyToken(refreshToken);
    
    // Ensure it's an admin token
    if (decoded.type !== 'admin') {
      throw new Error('Invalid refresh token');
    }

    // Find admin to ensure they still exist and are active
    const admin = await Admin.findByPk(decoded.userId);
    
    if (!admin) {
      throw new Error('Admin not found');
    }

    if (admin.status === 'inactive') {
      throw new Error('Admin account is inactive');
    }

    // Generate new tokens
    const tokenPayload = {
      userId: admin.id,
      type: 'admin',
      role: admin.role,
    };
    
    const newToken = generateToken(tokenPayload);
    const newRefreshToken = generateRefreshToken(tokenPayload);

    logger.info(`Admin token refreshed: ${admin.username} (${admin.id})`);

    return {
      token: newToken,
      refreshToken: newRefreshToken,
    };
  } catch (error) {
    logger.error('Admin token refresh error:', error);
    throw error;
  }
};

/**
 * Get admin profile by ID
 * @param {string} adminId - Admin ID
 * @returns {Object} Admin profile
 */
const getAdminProfile = async (adminId) => {
  try {
    const admin = await Admin.findByPk(adminId, {
      attributes: { exclude: ['password'] },
    });

    if (!admin) {
      throw new Error('Admin not found');
    }

    return admin;
  } catch (error) {
    logger.error('Get admin profile error:', error);
    throw error;
  }
};

module.exports = {
  loginAdmin,
  getAdminProfile,
  refreshAdminToken,
};
