const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Schema per le coordinate
const CoordinatesSchema = new Schema({
  lat: {
    type: Number,
    required: true
  },
  lng: {
    type: Number,
    required: true
  }
}, { _id: false });

// Schema per località
const LocationSchema = new Schema({
  city: {
    type: String,
    required: true,
    trim: true
  },
  address: {
    type: String,
    trim: true
  },
  province: {
    type: String,
    trim: true
  },
  coordinates: {
    type: CoordinatesSchema,
    required: true
  }
}, { _id: false });

const RideRequestSchema = new Schema({
  idapp: {
    type: String,
    required: true,
    index: true
  },
  rideId: {
    type: Schema.Types.ObjectId,
    ref: 'Ride',
    required: true,
    index: true
  },
  passengerId: {
    type: Schema.Types.ObjectId,
    ref: 'User',
    required: true,
    index: true
  },
  driverId: {
    type: Schema.Types.ObjectId,
    ref: 'User',
    required: true,
    index: true
  },
  message: {
    type: String,
    trim: true,
    maxlength: 500
  },
  pickupPoint: {
    type: LocationSchema
  },
  dropoffPoint: {
    type: LocationSchema
  },
  useOriginalRoute: {
    type: Boolean,
    default: true
    // true = usa partenza/destinazione originali del ride
  },
  seatsRequested: {
    type: Number,
    required: true,
    min: 1,
    default: 1
  },
  hasLuggage: {
    type: Boolean,
    default: false
  },
  luggageSize: {
    type: String,
    enum: ['small', 'medium', 'large'],
    default: 'small'
  },
  hasPackages: {
    type: Boolean,
    default: false
  },
  packageDescription: {
    type: String,
    trim: true,
    maxlength: 200
  },
  hasPets: {
    type: Boolean,
    default: false
  },
  petType: {
    type: String,
    trim: true
  },
  petSize: {
    type: String,
    enum: ['small', 'medium', 'large']
  },
  specialNeeds: {
    type: String,
    trim: true,
    maxlength: 300
  },
  status: {
    type: String,
    enum: ['pending', 'accepted', 'rejected', 'cancelled', 'expired', 'completed'],
    default: 'pending',
    index: true
  },
  responseMessage: {
    type: String,
    trim: true,
    maxlength: 500
  },
  respondedAt: {
    type: Date
  },
  contribution: {
    agreed: {
      type: Boolean,
      default: false
    },
    contribTypeId: {
      type: Schema.Types.ObjectId,
      ref: 'Contribtype'
    },
    amount: {
      type: Number,
      min: 0
    },
    notes: {
      type: String,
      trim: true
    }
  },
  cancelledBy: {
    type: String,
    enum: ['passenger', 'driver']
  },
  cancellationReason: {
    type: String,
    trim: true
  },
  cancelledAt: {
    type: Date
  },
  completedAt: {
    type: Date
  },
  feedbackGiven: {
    type: Boolean,
    default: false
  }
}, {
  timestamps: true,
  toJSON: { virtuals: true },
  toObject: { virtuals: true }
});

// Indici composti per ricerche ottimizzate
RideRequestSchema.index({ rideId: 1, status: 1 });
RideRequestSchema.index({ passengerId: 1, status: 1 });
RideRequestSchema.index({ driverId: 1, status: 1 });
RideRequestSchema.index({ idapp: 1, createdAt: -1 });

// Virtual per verificare se la richiesta può essere cancellata
RideRequestSchema.virtual('canCancel').get(function() {
  return ['pending', 'accepted'].includes(this.status);
});

// Virtual per verificare se è in attesa
RideRequestSchema.virtual('isPending').get(function() {
  return this.status === 'pending';
});

// Metodo per accettare la richiesta
RideRequestSchema.methods.accept = async function(responseMessage = '') {
  this.status = 'accepted';
  this.responseMessage = responseMessage;
  this.respondedAt = new Date();
  
  // Aggiorna il ride con il passeggero confermato
  const Ride = mongoose.model('Ride');
  const ride = await Ride.findById(this.rideId);
  
  if (ride) {
    ride.confirmedPassengers.push({
      userId: this.passengerId,
      seats: this.seatsRequested,
      pickupPoint: this.pickupPoint || ride.departure,
      dropoffPoint: this.dropoffPoint || ride.destination,
      confirmedAt: new Date()
    });
    await ride.updateAvailableSeats();
  }
  
  return this.save();
};

// Metodo per rifiutare la richiesta
RideRequestSchema.methods.reject = function(responseMessage = '') {
  this.status = 'rejected';
  this.responseMessage = responseMessage;
  this.respondedAt = new Date();
  return this.save();
};

// Metodo per cancellare la richiesta
RideRequestSchema.methods.cancel = async function(cancelledBy, reason = '') {
  this.status = 'cancelled';
  this.cancelledBy = cancelledBy;
  this.cancellationReason = reason;
  this.cancelledAt = new Date();
  
  // Se era accettata, rimuovi il passeggero dal ride
  if (this.status === 'accepted') {
    const Ride = mongoose.model('Ride');
    const ride = await Ride.findById(this.rideId);
    
    if (ride) {
      ride.confirmedPassengers = ride.confirmedPassengers.filter(
        p => p.userId.toString() !== this.passengerId.toString()
      );
      await ride.updateAvailableSeats();
    }
  }
  
  return this.save();
};

// Metodo statico per ottenere richieste pendenti di un conducente
RideRequestSchema.statics.getPendingForDriver = function(idapp, driverId) {
  return this.find({
    idapp,
    driverId,
    status: 'pending'
  })
  .populate('passengerId', 'username name surname email')
  .populate('rideId', 'departure destination dateTime')
  .sort({ createdAt: -1 });
};

// Metodo statico per ottenere richieste di un passeggero
RideRequestSchema.statics.getByPassenger = function(idapp, passengerId, status = null) {
  const query = { idapp, passengerId };
  if (status) {
    query.status = status;
  }
  return this.find(query)
    .populate('rideId')
    .populate('driverId', 'username name surname')
    .sort({ createdAt: -1 });
};

// Pre-save hook per validazioni
RideRequestSchema.pre('save', async function(next) {
  if (this.isNew) {
    // Verifica che il ride esista e abbia posti disponibili
    const Ride = mongoose.model('Ride');
    const ride = await Ride.findById(this.rideId);
    
    if (!ride) {
      throw new Error('Viaggio non trovato');
    }
    
    if (ride.type === 'offer' && ride.passengers.available < this.seatsRequested) {
      throw new Error('Posti non sufficienti per questo viaggio');
    }
    
    if (ride.userId.toString() === this.passengerId.toString()) {
      throw new Error('Non puoi richiedere un passaggio per il tuo stesso viaggio');
    }
    
    // Imposta il driverId dal ride
    this.driverId = ride.userId;
  }
  next();
});

const RideRequest = mongoose.model('RideRequest', RideRequestSchema);

module.exports = RideRequest;