const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

class Pharmacist {
  /**
   * Fetch all active pharmacists with optional filtering, search, and pagination
   */
  static async findAllActive(options = {}) {
    const {
      page = 1,
      limit = 10,
      search = '',
      filter = {},
      populate = '',
      sort = '-createdAt'
    } = options;

    try {
      const model = PharmacistModel;

      const query = { status: { $ne: 'deleted' }, ...filter };

      if (search) {
        query.$or = [
          { name: { $regex: search, $options: 'i' } },
          { email: { $regex: search, $options: 'i' } },
          { employee_id: { $regex: search, $options: 'i' } }
        ];
      }

      const total = await model.countDocuments(query);

      let queryBuilder = model.find(query)
        .sort(sort)
        .skip((page - 1) * limit)
        .limit(parseInt(limit));

      if (populate) queryBuilder = queryBuilder.populate(populate);

      const pharmacists = await queryBuilder.lean();

      return {
        pharmacists,
        pagination: {
          total,
          page: parseInt(page),
          pages: Math.ceil(total / limit),
          limit: parseInt(limit)
        }
      };
    } catch (error) {
      console.error('Error in Pharmacist.findAllActive:', error);
      throw error;
    }
  }

  /**
   * Find pharmacist by ID with details
   */
  static async findByIdWithDetails(id) {
    return this.model.findById(id)
      .populate('store', 'name address phone')
      .populate('user', 'name email phone')
      .lean();
  }

  /**
   * Create new pharmacist with the same ID as the user
   */
  static async createPharmacist(data) {
    const { user } = data;
    
    // If user ID is provided, use it as the _id for the pharmacist
    if (user) {
      // Check if a pharmacist with this ID already exists
      const existing = await this.model.findById(user);
      if (existing) throw new Error('Pharmacist with this user ID already exists');
      
      // Set the _id to match the user ID
      data._id = user;
    }
    
    // Check if email already exists
    const emailExists = await this.model.findOne({ email: data.email });
    if (emailExists) throw new Error('Email already exists');
    
    return this.model.create(data);
  }

  /**
   * Update pharmacist by ID
   */
  static async updatePharmacist(id, data) {
    if (data.email) {
      const existing = await this.model.findOne({
        email: data.email,
        _id: { $ne: id }
      });
      if (existing) throw new Error('Email already exists');
    }

    return this.model.findByIdAndUpdate(
      id,
      { $set: data },
      { new: true, runValidators: true }
    );
  }

  /**
   * Soft delete pharmacist
   */
  static async deletePharmacist(id) {
    return this.model.findByIdAndUpdate(
      id,
      { $set: { status: 'deleted' } },
      { new: true }
    );
  }

  /**
   * Get pharmacist statistics
   */
  static async getStatistics() {
    const [total, active, inactive, onLeave] = await Promise.all([
      this.model.countDocuments({ status: { $ne: 'deleted' } }),
      this.model.countDocuments({ status: 'active' }),
      this.model.countDocuments({ status: 'inactive' }),
      this.model.countDocuments({ status: 'on_leave' })
    ]);

    return {
      total,
      active,
      inactive,
      onLeave
    };
  }

  /**
   * Find pharmacist by credentials (email/password)
   */
  static async findByCredentials(email, password) {
    // Find pharmacist by email
    const pharmacist = await this.model.findOne({ email });
    
    if (!pharmacist) {
      throw new Error('Invalid credentials');
    }

    // Check if pharmacist is active
    if (pharmacist.status !== 'active') {
      throw new Error('Your account is not active. Please contact support.');
    }

    // Get the associated user to verify password
    const user = await mongoose.model('User').findById(pharmacist.user);
    
    if (!user) {
      throw new Error('User account not found');
    }

    // Check if password matches
    const isMatch = await user.matchPassword(password);
    
    if (!isMatch) {
      throw new Error('Invalid credentials');
    }

    return pharmacist;
  }
}

// Pharmacist schema
const pharmacistSchema = new mongoose.Schema({
  _id: {
    type: mongoose.Schema.Types.ObjectId,
    required: true
  },
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  store: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Store',
    required: true
  },
  name: {
    type: String,
    required: [true, 'Name is required'],
    trim: true
  },
  email: {
    type: String,
    required: [true, 'Email is required'],
    unique: true,
    trim: true,
    lowercase: true,
    match: [/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, 'Please provide a valid email']
  },
  password: {
    type: String,
    select: false // Don't return password in queries by default
  },
  phone: {
    type: String,
    trim: true
  },
  employee_id: {
    type: String,
    trim: true
  },
  qualification: {
    type: String,
    trim: true
  },
  license_number: {
    type: String,
    trim: true
  },
  experience_years: {
    type: Number,
    min: 0,
    default: 0
  },
  shift: {
    type: String,
    enum: ['morning', 'afternoon', 'night'],
    default: 'morning'
  },
  performance_rating: {
    type: Number,
    min: 0,
    max: 5,
    default: 0
  },
  status: {
    type: String,
    enum: ['active', 'inactive', 'on_leave', 'deleted'],
    default: 'active'
  },
  image: {
    type: String,
    default: ''
  },
  joining_date: {
    type: Date,
    default: Date.now
  },
  prescriptions_verified: {
    type: Number,
    default: 0
  }
}, { timestamps: true });

// Add method to compare entered password with hashed password
pharmacistSchema.methods.matchPassword = async function(enteredPassword) {
  try {
    if (!enteredPassword) {
      console.error('No password provided for comparison');
      return false;
    }
    if (!this.password) {
      console.error('No hashed password found for pharmacist');
      return false;
    }
    
    console.log('Comparing passwords in Pharmacist model...');
    console.log('Entered password length:', enteredPassword.length);
    console.log('Stored password hash exists:', !!this.password);
    
    return await bcrypt.compare(enteredPassword, this.password);
  } catch (error) {
    console.error('Error in matchPassword:', error);
    return false;
  }
};

// Hash password before saving
pharmacistSchema.pre('save', async function(next) {
  try {
    // Only hash the password if it has been modified (or is new)
    if (!this.isModified('password')) return next();
    
    if (!this.password) {
      console.error('No password provided for hashing');
      return next(new Error('Password is required'));
    }
    
    console.log('Hashing password for pharmacist:', this.email);
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
    next();
  } catch (error) {
    console.error('Error hashing password:', error);
    next(error);
  }
});

// Bind static methods
pharmacistSchema.statics.findAllActive = Pharmacist.findAllActive;
pharmacistSchema.statics.findByIdWithDetails = Pharmacist.findByIdWithDetails;
pharmacistSchema.statics.createPharmacist = Pharmacist.createPharmacist;
pharmacistSchema.statics.updatePharmacist = Pharmacist.updatePharmacist;
pharmacistSchema.statics.deletePharmacist = Pharmacist.deletePharmacist;
pharmacistSchema.statics.getStatistics = Pharmacist.getStatistics;

// Create and export the model
const PharmacistModel = mongoose.model('Pharmacist', pharmacistSchema);
Pharmacist.model = PharmacistModel;

module.exports = PharmacistModel;
