const mongoose = require('mongoose');
const BaseModel = require('./BaseModel');

const userAddressSchema = new mongoose.Schema({
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  address: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Address',
    required: true
  },
  isDefault: {
    type: Boolean,
    default: false
  }
}, {
  timestamps: true,
  toJSON: { virtuals: true },
  toObject: { virtuals: true }
});

// Add a compound index to ensure one default address per user
userAddressSchema.index({ user: 1, isDefault: 1 });

class UserAddress extends BaseModel {
  static get schema() {
    return userAddressSchema;
  }

  static async create(userAddressData) {
    const { user, address, isDefault = false } = userAddressData;
    
    try {
      // If setting as default, unset any existing default
      if (isDefault) {
        await this.model.updateMany(
          { user, isDefault: true },
          { $set: { isDefault: false } }
        );
      }
      
      // Create the user address
      const userAddress = new this.model({
        user,
        address,
        isDefault
      });
      
      await userAddress.save();
      return userAddress;
    } catch (error) {
      console.error('Error creating user address:', error);
      throw error;
    }
  }

  static async getByUser(userId, includeAddressDetails = true) {
    try {
      const query = this.model
        .find({ user: userId })
        .sort({ isDefault: -1, updatedAt: -1 });
      
      if (includeAddressDetails) {
        query.populate('address', '-__v -createdAt -updatedAt');
      }
      
      const userAddresses = await query.exec();
      
      return userAddresses.map(userAddress => ({
        ...userAddress.toObject().address?.toObject(),
        id: userAddress._id,
        is_default: userAddress.isDefault,
        address_id: userAddress.address?._id
      }));
    } catch (error) {
      console.error('Error getting user addresses:', error);
      throw error;
    }
  }

  static async getDefaultAddress(userId) {
    try {
      const userAddress = await this.model
        .findOne({ user: userId, isDefault: true })
        .populate('address', '-__v -createdAt -updatedAt')
        .exec();
      
      if (!userAddress) return null;
      
      return {
        ...userAddress.toObject().address.toObject(),
        id: userAddress._id,
        is_default: userAddress.isDefault
      };
    } catch (error) {
      console.error('Error getting default address:', error);
      throw error;
    }
  }

  static async deleteUserAddress(userId, addressId) {
    const session = await mongoose.startSession();
    session.startTransaction();
    
    try {
      // First check if this is the last address
      const count = await this.model.countDocuments({ user: userId });
      if (count <= 1) {
        throw new Error('Cannot delete the only address. Please add another address first.');
      }
      
      // Delete the user address
      const result = await this.model.findOneAndDelete({
        _id: addressId,
        user: userId
      }).session(session);
      
      // If this was the default, set another address as default
      if (result?.isDefault) {
        const newDefault = await this.model.findOne({ user: userId }).session(session);
        if (newDefault) {
          newDefault.isDefault = true;
          await newDefault.save({ session });
        }
      }
      
      await session.commitTransaction();
      return result !== null;
    } catch (error) {
      await session.abortTransaction();
      console.error('Error deleting user address:', error);
      throw error;
    } finally {
      session.endSession();
    }
  }
}

// Create the model using the schema
UserAddress._model = mongoose.model('UserAddress', userAddressSchema);

module.exports = UserAddress;
