import mongoose, { Schema, Document, model } from "mongoose";
import bcrypt from "bcryptjs";

interface IReservedAccountDetails extends Document {
  accountName: string;
  accountReferences: string;
  reservationReference: string;
  accounts: {
    bankCode: string;
    bankName: string;
    accountNumber: string;
    accountName: string;
  }[];
}
interface IReferral extends Document {
  referrerId: mongoose.Schema.Types.ObjectId;
  referredId: mongoose.Schema.Types.ObjectId;
}

interface IReferralDeposit extends Document {
  referredId: mongoose.Schema.Types.ObjectId;
  amount: number;
  referrerCredit: number;
}

export interface IAuthenticator {
  credentialID: Buffer;
  credentialPublicKey: Buffer;
  counter: number;
  transports?: AuthenticatorTransport[];
}

//
export interface IUser extends Document {
  _id: string;
  username: string;
  firstName: string;
  middleName: string;
  lastName: string;
  name: string;
  email: string;
  role: "admin" | "user";
  userType: "Smart Earner" | "TopUser" | "API User" | "Affiliate User";
  mobileNumber: string;
  accountBalance: number;
  reservedAccountDetails: IReservedAccountDetails[];
  dateOfBirth: Date;
  bvn: string;
  nin: string;
  image: string;
  transactionPin: string;
  referredBy: mongoose.Types.ObjectId[];
  referralCode: string | null;
  refererBonus: number;
  thumbprintStatus: boolean;
  transactionStatus: boolean;
  lastLogin: Date | null;
  webhookUrl: string;
  dateJoined: Date;
  authenticators?: IAuthenticator[];
  // webAuthCredentials: WebAuthCredential[];
  currentChallenge?: string;
  // webAuthChallenge?: string; // Added for challenge storage
  hasSeenModal: boolean;
  hasTransactionPin: boolean;
  transactionPinResetCode: number;
  transactionPinResetExpires: Date;
  failedResetAttempts: number;
}

const authenticatorSchema = new Schema<IAuthenticator>({
  credentialID: { type: Buffer, required: true },
  credentialPublicKey: { type: Buffer, required: true },
  counter: { type: Number, required: true },
  transports: { type: [String] },
});

const referralSchema = new Schema<IReferral>(
  {
    referrerId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
    referredId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
  },
  { timestamps: true }
);

const referralDepositSchema = new Schema<IReferralDeposit>(
  {
    referredId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
    amount: { type: Number },
    referrerCredit: { type: Number },
  },
  { timestamps: true }
);

const reservedAccountDetailsSchema = new Schema<IReservedAccountDetails>({
  accountName: { type: String, default: "" },
  accountReferences: { type: String, default: "" },
  reservationReference: { type: String, default: "" },
  accounts: [
    {
      bankCode: { type: String, default: "" },
      bankName: { type: String, default: "" },
      accountNumber: { type: String, default: "" },
      accountName: { type: String, default: "" },
    },
  ],
});

// const webAuthCredentialSchema = new Schema<WebAuthCredential>({
//   credentialID: { type: String, required: true }, // Base64URL
//   credentialPublicKey: { type: String, required: true }, // Base64URL
//   transports: { type: [String], default: [] },
//   counter: { type: Number, required: true },
// });

const userSchema = new Schema<IUser>(
  {
    username: { type: String, unique: true },
    firstName: { type: String },
    middleName: { type: String },
    lastName: { type: String },
    name: { type: String },
    email: { type: String, unique: true },
    role: { type: String, enum: ["admin", "user"] },
    userType: {
      type: String,
      enum: ["Smart Earner", "TopUser", "API User", "Affiliate User"],
      default: "Smart Earner",
    },
    mobileNumber: { type: String },
    accountBalance: { type: Number, default: 0 },
    reservedAccountDetails: [reservedAccountDetailsSchema],
    bvn: { type: String },
    nin: { type: String },
    image: { type: String, default: "" },
    dateOfBirth: { type: Date },
    transactionPin: { type: String },
    referralCode: { type: String, unique: true },
    referredBy: [
      { type: mongoose.Schema.Types.ObjectId, ref: "User", default: [] },
    ],
    refererBonus: { type: Number, default: 0 },
    thumbprintStatus: { type: Boolean, default: false },
    transactionStatus: { type: Boolean, default: false },
    lastLogin: { type: Date, default: null },
    dateJoined: { type: Date, default: Date.now },
    webhookUrl: { type: String },
    currentChallenge: { type: String },
    authenticators: [authenticatorSchema],
    hasSeenModal: { type: Boolean, default: false },
    hasTransactionPin: { type: Boolean, default: false },
    transactionPinResetCode: { type: Number },
    transactionPinResetExpires: { type: Date },
    failedResetAttempts: { type: Number, default: 0 },
  },
  {
    timestamps: true,
    toJSON: { virtuals: true },
    toObject: { virtuals: true },
  }
);

interface IAdminSettings extends Document {
  firstDepositPercentage: number; // Default 10%
  subsequentDepositPercentage: number; // Default 5%
  depositFeePercentage: number;
}
const adminSettingsSchema = new Schema<IAdminSettings>({
  firstDepositPercentage: { type: Number, default: 1.5 }, // Default 10%
  subsequentDepositPercentage: { type: Number, default: 0.5 }, // Default 5%
  depositFeePercentage: { type: Number, default: 1.5 },
});

userSchema.pre<IUser>("save", async function (this: IUser, next: () => void) {
  if (this.isModified("transactionPin")) {
    const salt = await bcrypt.genSalt(10);
    this.transactionPin = await bcrypt.hash(this.transactionPin, salt);
  }
  next();
});

userSchema.virtual("referrals", {
  ref: "Referral",
  localField: "_id",
  foreignField: "referrerId",
});

export const User = mongoose.models.User || model<IUser>("User", userSchema);
export const Referral =
  mongoose.models.Referral || model<IReferral>("Referral", referralSchema);
export const ReferralDeposit =
  mongoose.models.ReferralDeposit ||
  model<IReferralDeposit>("ReferralDeposit", referralDepositSchema);
export const AdminSettings =
  mongoose.models.AdminSettings ||
  model<IAdminSettings>("AdminSettings", adminSettingsSchema);
