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

const FeedbackCategoriesSchema = new Schema(
  {
    punctuality: {
      type: Number,
      min: 1,
      max: 5,
    },
    cleanliness: {
      type: Number,
      min: 1,
      max: 5,
    },
    communication: {
      type: Number,
      min: 1,
      max: 5,
    },
    driving: {
      type: Number,
      min: 1,
      max: 5,
      // Solo per feedback a conducenti
    },
    respect: {
      type: Number,
      min: 1,
      max: 5,
    },
    reliability: {
      type: Number,
      min: 1,
      max: 5,
    },
  },
  { _id: false }
);

const FeedbackSchema = new Schema(
  {
    idapp: {
      type: String,
      required: true,
      index: true,
    },
    rideId: {
      type: Schema.Types.ObjectId,
      ref: 'Ride',
      required: true,
      index: true,
    },
    rideRequestId: {
      type: Schema.Types.ObjectId,
      ref: 'RideRequest',
    },
    fromUserId: {
      type: Schema.Types.ObjectId,
      ref: 'User',
      required: true,
      index: true,
    },
    toUserId: {
      type: Schema.Types.ObjectId,
      ref: 'User',
      required: true,
      index: true,
    },
    role: {
      type: String,
      enum: ['driver', 'passenger'],
      required: true,
      // Il ruolo dell'utente che RICEVE il feedback
      // 'driver' = sto valutando il conducente
      // 'passenger' = sto valutando il passeggero
    },
    rating: {
      type: Number,
      required: true,
      min: 1,
      max: 5,
    },
    categories: {
      type: FeedbackCategoriesSchema,
    },
    comment: {
      type: String,
      trim: true,
      maxlength: 1000,
    },
    pros: [
      {
        type: String,
        trim: true,
      },
    ],
    cons: [
      {
        type: String,
        trim: true,
      },
    ],
    tags: [
      {
        type: String,
        enum: [
          'puntuale',
          'gentile',
          'auto_pulita',
          'guida_sicura',
          'buona_conversazione',
          'silenzioso',
          'flessibile',
          'rispettoso',
          'affidabile',
          'consigliato',
          // Tag negativi
          'in_ritardo',
          'scortese',
          'guida_pericolosa',
          'auto_sporca',
          'non_rispettoso',
        ],
      },
    ],
    isPublic: {
      type: Boolean,
      default: true,
    },
    isVerified: {
      type: Boolean,
      default: false,
      // Feedback verificato (viaggio effettivamente completato)
    },
    response: {
      text: {
        type: String,
        trim: true,
        maxlength: 500,
      },
      respondedAt: {
        type: Date,
      },
    },
    helpful: {
      count: {
        type: Number,
        default: 0,
      },
      users: [
        {
          type: Schema.Types.ObjectId,
          ref: 'User',
        },
      ],
    },
    reported: {
      isReported: {
        type: Boolean,
        default: false,
      },
      reason: String,
      reportedBy: {
        type: Schema.Types.ObjectId,
        ref: 'User',
      },
      reportedAt: Date,
    },
  },
  {
    timestamps: true,
    toJSON: { virtuals: true },
    toObject: { virtuals: true },
  }
);

// Indici composti
FeedbackSchema.index({ toUserId: 1, role: 1 });
FeedbackSchema.index({ rideId: 1, fromUserId: 1 });
FeedbackSchema.index({ idapp: 1, toUserId: 1 });

// Vincolo: un utente può lasciare un solo feedback per viaggio verso un altro utente
FeedbackSchema.index({ rideId: 1, fromUserId: 1, toUserId: 1 }, { unique: true });

// Virtual per calcolare media categorie
FeedbackSchema.virtual('categoryAverage').get(function () {
  if (!this.categories) return null;
  const cats = this.categories.toObject ? this.categories.toObject() : this.categories;
  const values = Object.values(cats).filter((v) => typeof v === 'number');
  if (values.length === 0) return null;
  return values.reduce((a, b) => a + b, 0) / values.length;
});

// Metodo per aggiungere risposta
FeedbackSchema.methods.addResponse = function (text) {
  this.response = {
    text,
    respondedAt: new Date(),
  };
  return this.save();
};

// Metodo per segnare come utile
FeedbackSchema.methods.markAsHelpful = function (userId) {
  if (!this.helpful.users.includes(userId)) {
    this.helpful.users.push(userId);
    this.helpful.count = this.helpful.users.length;
    return this.save();
  }
  return Promise.resolve(this);
};

// Metodo per segnalare feedback
FeedbackSchema.methods.report = function (userId, reason) {
  this.reported = {
    isReported: true,
    reason,
    reportedBy: userId,
    reportedAt: new Date(),
  };
  return this.save();
};

// Metodo statico per ottenere feedback di un utente
FeedbackSchema.statics.getForUser = function (idapp, userId, options = {}) {
  const query = {
    idapp,
    toUserId: userId,
    isPublic: true,
  };

  if (options.role) {
    query.role = options.role;
  }

  return this.find(query)
    .populate('fromUserId', 'username name surname profile.avatar')
    .populate('rideId', 'departure destination dateTime')
    .sort({ createdAt: -1 })
    .limit(options.limit || 20);
};

// Metodo statico per calcolare statistiche
FeedbackSchema.statics.getStatsForUser = async function (idapp, userId) {
  const stats = await this.aggregate([
    {
      $match: {
        idapp,
        toUserId: new mongoose.Types.ObjectId(userId),
      },
    },
    {
      $group: {
        _id: '$role',
        averageRating: { $avg: '$rating' },
        totalFeedbacks: { $sum: 1 },
        avgPunctuality: { $avg: '$categories.punctuality' },
        avgCleanliness: { $avg: '$categories.cleanliness' },
        avgCommunication: { $avg: '$categories.communication' },
        avgDriving: { $avg: '$categories.driving' },
        avgRespect: { $avg: '$categories.respect' },
        avgReliability: { $avg: '$categories.reliability' },
      },
    },
  ]);

  // Trasforma in oggetto più leggibile
  const result = {
    asDriver: null,
    asPassenger: null,
    overall: {
      averageRating: 0,
      totalFeedbacks: 0,
    },
  };

  stats.forEach((stat) => {
    const data = {
      averageRating: Math.round(stat.averageRating * 10) / 10,
      totalFeedbacks: stat.totalFeedbacks,
      categories: {
        punctuality: stat.avgPunctuality ? Math.round(stat.avgPunctuality * 10) / 10 : null,
        cleanliness: stat.avgCleanliness ? Math.round(stat.avgCleanliness * 10) / 10 : null,
        communication: stat.avgCommunication ? Math.round(stat.avgCommunication * 10) / 10 : null,
        driving: stat.avgDriving ? Math.round(stat.avgDriving * 10) / 10 : null,
        respect: stat.avgRespect ? Math.round(stat.avgRespect * 10) / 10 : null,
        reliability: stat.avgReliability ? Math.round(stat.avgReliability * 10) / 10 : null,
      },
    };

    if (stat._id === 'driver') {
      result.asDriver = data;
    } else if (stat._id === 'passenger') {
      result.asPassenger = data;
    }
  });

  // Calcola overall
  const allStats = stats.reduce(
    (acc, s) => {
      acc.total += s.totalFeedbacks;
      acc.sum += s.averageRating * s.totalFeedbacks;
      return acc;
    },
    { total: 0, sum: 0 }
  );

  if (allStats.total > 0) {
    result.overall = {
      averageRating: Math.round((allStats.sum / allStats.total) * 10) / 10,
      totalFeedbacks: allStats.total,
    };
  }

  return result;
};

// Metodo statico per contare distribuzioni rating
FeedbackSchema.statics.getRatingDistribution = async function (idapp, userId, role = null) {
  const match = {
    idapp,
    toUserId: new mongoose.Types.ObjectId(userId),
  };
  if (role) match.role = role;

  return this.aggregate([
    { $match: match },
    {
      $group: {
        _id: '$rating',
        count: { $sum: 1 },
      },
    },
    { $sort: { _id: -1 } },
  ]);
};

// Hook post-save per aggiornare rating utente
FeedbackSchema.post('save', async function (doc) {
  try {
    const { User } = require('./User');

    const stats = await mongoose.model('Feedback').getStatsForUser(doc.idapp, doc.toUserId);

    await User.findByIdAndUpdate(doc.toUserId, {
      'profile.driverProfile.averageRating': stats.overall.averageRating,
      'profile.driverProfile.totalRatings': stats.overall.totalFeedbacks,
    });
  } catch (error) {
    console.error('Errore aggiornamento rating utente:', error);
  }
});

const Feedback = mongoose.model('Feedback', FeedbackSchema);

module.exports = Feedback;
