import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
import { ExperienceLevel } from '../../../common/enums/experience-level.enum';
import { MusicRole } from '../../../common/enums/music-role.enum';
import { UserRole } from '../../../common/enums/user-role.enum';
import {
  resolveManagedFileUrl,
  resolveManagedFileUrls,
} from '../../../common/utils/public-url.util';

export type UserDocument = HydratedDocument<User>;

@Schema({ timestamps: true, versionKey: false })
export class User {
  @Prop({ required: true, trim: true, minlength: 2, maxlength: 80 })
  name!: string;

  @Prop({ default: '', trim: true, maxlength: 80, index: true })
  stageName!: string;

  @Prop({
    required: true,
    trim: true,
    lowercase: true,
    unique: true,
    index: true,
    minlength: 3,
    maxlength: 30,
  })
  username!: string;

  @Prop({ required: true, trim: true, lowercase: true, unique: true, index: true })
  email!: string;

  @Prop({ required: true, minlength: 8, select: false })
  password!: string;

  @Prop({ type: String, required: false, unique: true, sparse: true, index: true })
  googleId?: string;

  @Prop({ default: 'local', enum: ['local', 'google'], index: true })
  authProvider!: 'local' | 'google';

  @Prop({ type: String, enum: Object.values(UserRole), default: UserRole.USER, index: true })
  role!: UserRole;

  @Prop({ default: false, index: true })
  isDisabled!: boolean;

  @Prop({ type: Date, required: false })
  disabledAt?: Date;

  @Prop({ default: '', maxlength: 300 })
  disabledReason!: string;

  @Prop({ type: String, required: false, index: true })
  disabledBy?: string;

  @Prop({ default: '', maxlength: 160 })
  bio!: string;

  @Prop({ default: '' })
  avatar!: string;

  @Prop({ default: '' })
  coverImage!: string;

  @Prop({ default: '' })
  location!: string;

  @Prop({ type: Number, min: -90, max: 90, default: null })
  latitude!: number | null;

  @Prop({ type: Number, min: -180, max: 180, default: null })
  longitude!: number | null;

  @Prop({ type: [String], enum: Object.values(MusicRole), default: [] })
  musicRoles!: MusicRole[];

  @Prop({ type: String, enum: Object.values(ExperienceLevel), default: ExperienceLevel.BEGINNER })
  experienceLevel!: ExperienceLevel;

  @Prop({ type: [String], default: [] })
  musicGenres!: string[];

  @Prop({ type: [String], default: [] })
  favoriteInstruments!: string[];

  @Prop({ type: [String], default: [] })
  favoriteMaqamat!: string[];

  @Prop({ default: '', trim: true, maxlength: 80 })
  preferredMood!: string;

  @Prop({ default: 0, min: 0 })
  followersCount!: number;

  @Prop({ default: 0, min: 0 })
  followingCount!: number;

  @Prop({ default: 0, min: 0 })
  postsCount!: number;

  @Prop({ default: false })
  isPrivate!: boolean;

  @Prop({ default: false, index: true })
  isVerified!: boolean;

  @Prop({ default: false })
  isEmailVerified!: boolean;

  @Prop({ default: false, index: true })
  isOnline!: boolean;

  @Prop({ type: Date, default: null })
  lastSeenAt?: Date | null;

  @Prop({ default: '', trim: true, maxlength: 120 })
  shopName!: string;

  @Prop({ default: '', trim: true, maxlength: 2000 })
  shopDescription!: string;

  @Prop({ type: [String], default: [] })
  shopImageUrls!: string[];

  @Prop({ default: '', trim: true, maxlength: 160 })
  shopLocation!: string;

  @Prop({ type: Number, min: -90, max: 90, default: null })
  shopLatitude!: number | null;

  @Prop({ type: Number, min: -180, max: 180, default: null })
  shopLongitude!: number | null;
}

export const UserSchema = SchemaFactory.createForClass(User);

UserSchema.index({ createdAt: -1 });
UserSchema.index({ name: 1, isDisabled: 1 });
UserSchema.index(
  { username: 'text', name: 'text', stageName: 'text' },
  { name: 'user_search_text' },
);

const stripLegacyRoleFlags = (_doc: unknown, ret: any) => {
  delete ret.isInstrumentalist;
  delete ret.isSinger;
  delete ret.isComposer;
  delete ret.isLyricist;
  ret.avatar = resolveManagedFileUrl(ret.avatar);
  ret.coverImage = resolveManagedFileUrl(ret.coverImage);
  ret.shopImageUrls = resolveManagedFileUrls(ret.shopImageUrls);
  return ret;
};

UserSchema.set('toJSON', { transform: stripLegacyRoleFlags });
UserSchema.set('toObject', { transform: stripLegacyRoleFlags });
