const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const BaseModel = require('./BaseModel');
const object = require('lodash');

class PickerPacker {
  // Define the schema as a static getter
  static get schema() {
    return new mongoose.Schema({
      _id: {
        type: mongoose.Schema.Types.ObjectId,
        required: true
      },
      user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User',
        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']
      },
      phone: {
        type: String,
        trim: true
      },
      employee_id: {
        type: String,
        trim: true
      },
      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'],
        default: 'active'
      },
      image: {
        type: String
      },
      joining_date: {
        type: Date,
        default: Date.now
      },
      orders_processed: {
        type: Number,
        default: 0
      },
      store: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Store',
        required: true
      }
    }, {
      timestamps: true,
      toJSON: { virtuals: true },
      toObject: { virtuals: true }
    });
  }

  /**
   * Find all active picker packers with optional filtering and pagination
   * @param {Object} options - Query options
   * @returns {Promise<Object>} - Object containing items and pagination info
   */
  static async findAllActive(options = {}) {
    const {
      page = 1,
      limit = 10,
      search = '',
      filter = {},
      populate = '',
      sort = '-createdAt'
    } = options;

    try {
      // Get the model instance using the static method
      const model = PickerPackerModel;
      
      // Build the query
      const query = { status: { $ne: 'deleted' }, ...filter };

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

      // Get total count using the model's countDocuments method
      const total = await model.countDocuments(query);
      
      // Build the query
      let queryBuilder = model.find(query)
        .sort(sort)
        .skip((page - 1) * limit)
        .limit(parseInt(limit));

      // Apply population if needed
      if (populate) {
        queryBuilder = queryBuilder.populate(populate);
      }

      // Execute the query
      const items = await queryBuilder.lean();

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

  /**
   * Find picker packer by ID with additional details
   * @param {String} id - Picker packer ID
   * @returns {Promise<Object>} - Picker packer with populated fields
   */
  static async findByIdWithDetails(id) {
    return this.model.findById(id)
      .populate('store', 'name address phone')
      .populate('user', 'name email phone')
      .lean();
  }

  /**
   * Create a new picker packer
   * @param {Object} data - Picker packer data
   * @returns {Promise<Object>} - Created picker packer
   */
  static async createPickerPacker(data) {
    // Check if email already exists
    const existingPickerPacker = await this.model.findOne({ email: data.email });
    if (existingPickerPacker) {
      throw new Error('Email already exists');
    }
    
    return this.model.create(data);
  }

  /**
   * Update picker packer by ID
   * @param {String} id - Picker packer ID
   * @param {Object} data - Updated data
   * @returns {Promise<Object>} - Updated picker packer
   */
  static async updatePickerPacker(id, data) {
    // Check if email already exists for another picker packer
    if (data.email) {
      const existingPickerPacker = await this.model.findOne({ 
        email: data.email,
        _id: { $ne: id }
      });
      
      if (existingPickerPacker) {
        throw new Error('Email already exists');
      }
    }
    
    return this.model.findByIdAndUpdate(
      id,
      { $set: data },
      { new: true, runValidators: true }
    );
  }

  /**
   * Delete picker packer (soft delete)
   * @param {String} id - Picker packer ID
   * @returns {Promise<Object>} - Deleted picker packer
   */
  static async deletePickerPacker(id) {
    return this.model.findByIdAndUpdate(
      id,
      { $set: { status: 'deleted' } },
      { new: true }
    );
  }

  /**
   * Get picker packer statistics
   * @returns {Promise<Object>} - Statistics object
   */
  static async getStatistics() {
    const total = await this.model.countDocuments();
    const active = await this.model.countDocuments({ status: 'active' });
    const inactive = await this.model.countDocuments({ status: 'inactive' });
    const onLeave = await this.model.countDocuments({ status: 'on_leave' });
    const morningShift = await this.model.countDocuments({ shift: 'morning' });
    const afternoonShift = await this.model.countDocuments({ shift: 'afternoon' });
    const nightShift = await this.model.countDocuments({ shift: 'night' });
    
    return {
      total,
      active,
      inactive,
      onLeave,
      shifts: {
        morning: morningShift,
        afternoon: afternoonShift,
        night: nightShift
      }
    };
  }
}

// Create the schema
const pickerPackerSchema = new mongoose.Schema({
  _id: {
    type: mongoose.Schema.Types.ObjectId,
    required: true
  },
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    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']
  },
  phone: {
    type: String,
    trim: true
  },
  password: {
    type: String,
    required: [true, 'Please enter a password'],
    minlength: 6,
    select: false
  },
  employee_id: {
    type: String,
    trim: true
  },
  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', 'deleted'],
    default: 'active'
  },
  image: {
    type: String,
    default: ''
  },
  joining_date: {
    type: Date,
    default: Date.now
  },
  orders_processed: {
    type: Number,
    default: 0
  },
  store: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Store',
    required: true
  }
}, { timestamps: true });

// Encrypt password using bcrypt
pickerPackerSchema.pre('save', async function(next) {
  if (!this.isModified('password')) {
    next();
  }

  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
});

// Sign JWT and return
pickerPackerSchema.methods.getSignedJwtToken = function() {
  return jwt.sign({ id: this._id, role: 'picker_packer' }, process.env.JWT_SECRET, {
    expiresIn: process.env.JWT_EXPIRE || '30d'
  });
};

// Match user entered password to hashed password in database
pickerPackerSchema.methods.matchPassword = async function(enteredPassword) {
  return await bcrypt.compare(enteredPassword, this.password);
};

// Add static methods
pickerPackerSchema.statics.findAllActive = PickerPacker.findAllActive;
pickerPackerSchema.statics.findByIdWithDetails = PickerPacker.findByIdWithDetails;
pickerPackerSchema.statics.createPickerPacker = PickerPacker.createPickerPacker;
pickerPackerSchema.statics.updatePickerPacker = PickerPacker.updatePickerPacker;
pickerPackerSchema.statics.deletePickerPacker = PickerPacker.deletePickerPacker;
pickerPackerSchema.statics.getStatistics = PickerPacker.getStatistics;

// Create and export the model
const PickerPackerModel = mongoose.model('PickerPacker', pickerPackerSchema);
module.exports = PickerPackerModel;