import mongoose, { Schema, Document } from 'mongoose';
import bcrypt from 'bcrypt';
// Import Company to ensure it's registered before User uses it in populate
import './Company';
import './Role';

export interface IUserDocument extends Document {
  _id: any;
  email: string;
  password: string;
  firstName?: string;
  lastName?: string;
  name: string;
  role: string;
  department?: string;
  status: 'Active' | 'Suspended' | 'Disabled';
  companyId?: any;
  scope: string[];
  avatar?: string;
  createdAt: Date;
  updatedAt: Date;
  comparePassword(candidatePassword: string): Promise<boolean>;
}

const userSchema = new Schema<IUserDocument>(
  {
    _id: { type: Schema.Types.Mixed, default: () => new mongoose.Types.ObjectId().toString() }, // Support both string demo IDs and auto-gen string IDs
    email: { type: String, required: true, unique: true, lowercase: true, trim: true },
    password: { type: String, required: true, select: false },
    firstName: String,
    lastName: String,
    name: { type: String, required: true },
    role: {
      type: String,
      required: true,
      // Role name must match an active role in the Role collection
      // Enum validation removed to allow dynamic roles from MongoDB
      default: 'Technician'
    },
    department: String,
    status: {
      type: String,
      enum: ['Active', 'Suspended', 'Disabled'],
      default: 'Active'
    },
    companyId: { type: Schema.Types.Mixed, ref: 'Company' },
    scope: [{ type: Schema.Types.Mixed, ref: 'Project' }],
    avatar: String,
  },
  {
    timestamps: true,
    strict: false,
  }
);

// Indexes
userSchema.index({ role: 1 });
userSchema.index({ status: 1 });

// Validate role exists in Role collection before saving
userSchema.pre('save', async function (next) {
  if (this.isModified('role')) {
    try {
      const { Role } = await import('./Role');
      const role = await Role.findOne({ name: this.role, isActive: true });
      if (!role) {
        return next(new Error(`Role "${this.role}" not found or inactive. Please use a valid role name.`));
      }
    } catch (error: any) {
      // If Role model not available or error, allow save but log warning
      console.warn(`[User Model] Could not validate role "${this.role}":`, error.message);
    }
  }
  next();
});

// Hash password before saving
userSchema.pre('save', async function (next) {
  if (!this.isModified('password')) return next();

  try {
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
    next();
  } catch (error: any) {
    next(error);
  }
});

// Method to compare password
userSchema.methods.comparePassword = async function (candidatePassword: string): Promise<boolean> {
  if (!this.password) return false;
  return bcrypt.compare(candidatePassword, this.password);
};

// Virtual for full name
userSchema.virtual('fullName').get(function () {
  return this.name || `${this.firstName || ''} ${this.lastName || ''}`.trim();
});

export const User = mongoose.model<IUserDocument>('User', userSchema);
