const mongoose = require('mongoose');
const { Schema } = mongoose;
const bcrypt = require('bcryptjs')
const jwt = require("jsonwebtoken");
const Zone = require('./zone.model');

// 1. Sub-schema for Documents
const DocumentSchema = new Schema({
  docType: {
    type: String,
    enum: ['gst', 'pan', 'address-proof', 'business-license', 'bank-statement', 'insurance', 'other']
  },
  fileUrl: { type: String, required: true },
  uploadDate: { type: Date, default: Date.now },
  isVerified: { type: Boolean, default: false }
});

// 2. Sub-schema for bank details
const AccountDetailsSchema = new Schema({
  accountHolderName: {
    type: String,
    required: [true, 'Account Holder Name is required']
  },
  accountNumber: {
    type: String,
    required: [true, 'Account Number is required']
  },
  ifscCode: {
    type: String,
    required: [true, 'IFSC Code is required']
  },
  bankName: {
    type: String,
    required: [true, 'Bank Name is required']
  },
  branchName: {
    type: String,
    required: [true, 'Branch Name is required']
  },
  upiId: {
    type: String,
    required: [true, 'UPI ID is required']
  },
  uploadDate: { type: Date, default: Date.now },
  isVerified: { type: Boolean, default: false }
});

//4. financial summary 
const FinancialSchema = new Schema({
  commissionType: {
    type: String,
    enum: ['flat', 'percentage'],
    default: 'percentage'
  },
  commissionAmount: {
    type: Number,
    default: 0
  },
  paymentCycle: {
    type: String,
    enum: ['daily', 'weekly', 'monthly'],
    default: 'weekly'
  },
  maximumPayoutThreshold: {
    type: Number,
    default: 0
  },
  taxDeduction: {
    type: Number,
    default: 0
  },
})

// 5. Wallet Schema for Settlement System
const WalletSchema = new Schema({
  balance: {
    type: Number,
    default: 0  // Can go negative (due amount)
  },
  totalEarnings: {
    type: Number,
    default: 0
  },
  totalWithdrawn: {
    type: Number,
    default: 0
  },
  pendingWithdrawal: {
    type: Number,
    default: 0
  },
  dueAmount: {
    type: Number,
    default: 0  // Tracks negative balance separately
  },
  lastUpdated: {
    type: Date,
    default: Date.now
  }
})

// 3. Main Vendor Schema
const VendorSchema = new Schema({
  vendorName: {
    type: String,
    required: [true, 'Vendor Name is required'],
    trim: true,
    index: true
  },
  displayName: {
    type: String,
    required: [true, 'Display Name is required'],
    trim: true
  },
  email: {
    type: String,
    required: [true, 'Email is required'],
    unique: true,
    lowercase: true,
    trim: true,
    match: [/\S+@\S+\.\S+/, 'Please use a valid email address'],
    index: true
  },
  phone: {
    type: String,
    required: [true, 'Phone number is required'],
    trim: true
  },
  password: {
    type: String,
    minlength: 6,
    select: false
  },
  role: {
    type: String,
    default: 'vendor'
  },
  vendorId: {
    type: String,
    unique: true,
    sparse: true
  },
  resetToken: String,
  resetTokenExpiry: Date,
  status: {
    type: String,
    enum: ['pending', 'active', 'inactive', 'suspended', 'rejected'],
    default: 'pending',
    index: true
  },
  operationalZone: {
    type: Schema.Types.ObjectId,
    ref: 'Zone',
    required: [true, 'Operational zone is required']
  },
  registeredAddress: {
    type: String,
    required: [true, 'Registered Address is required']
  },
  refreshToken: {
    type: [String],
    select: false
  },
  documents: [DocumentSchema],
  accountDetails: AccountDetailsSchema,
  financialSummary: FinancialSchema,

  // Wallet for Settlement System
  wallet: {
    type: WalletSchema,
    default: () => ({})
  },

  // Maximum due limit (negative balance limit)
  // If wallet.balance goes below this, vendor is blocked from bookings
  maxDueLimit: {
    type: Number,
    default: -2000  // Default: vendor can have up to ₹2000 due
  },

  // Audit fields
  createdBy: { type: Schema.Types.ObjectId, ref: 'User' },
  isDeleted: { type: Boolean, default: false }
}, {
  timestamps: true
});

// Pre-save hook to generate vendorId
VendorSchema.pre('save', async function (next) {
  if (!this.isNew || this.vendorId) {
    return next();
  }

  try {
    const { getEnv } = require("../utils/envLoader");
    const prefix = getEnv("VENDOR_ID_PREFIX") || process.env.VENDOR_ID_PREFIX || 'VND';

    // Count only non-deleted vendors to determine next sequence number
    const totalVendors = await this.constructor.countDocuments({ isDeleted: false });

    // Next sequence is total count + 1 (since this vendor is not saved yet)
    const nextSequence = totalVendors + 1;

    const zone = await Zone.findById(this.operationalZone);
    const zoneName = zone?.zoneName?.slice(0, 3).toUpperCase();
    // Pad with zeros (e.g., 0001)
    const paddedSequence = String(nextSequence).padStart(4, '0');
    this.vendorId = (`${prefix}${zoneName}${paddedSequence}`);
    // console.log(this.vendorId);
    next();
  } catch (error) {
    next(error);
  }
});

// --- IMPORTANT METHODS ---

// 1. Instance Method: Check if vendor is permitted to operate
VendorSchema.methods.canOperate = function () {
  return this.status === 'Active' && !this.isDeleted;
};

// 2. Instance Method: Verify a specific document
VendorSchema.methods.verifyDocument = function (docId) {
  const doc = this.documents.id(docId);
  if (doc) {
    doc.isVerified = true;
    return this.save();
  }
  throw new Error('Document not found');
};

// 3. Static Method: Find vendors by Operational Zone
VendorSchema.statics.findByZone = function (zoneId) {
  return this.find({
    operationalZone: zoneId,
    status: 'Active',
    isDeleted: false
  });
};

// 4. Static Method: Get pending approvals
VendorSchema.statics.findPending = function () {
  return this.find({ status: 'Pending' })
    .select('vendorName email createdAt')
    .sort({ createdAt: 1 });
};

VendorSchema.pre("save", function () {
  if (!this.isModified("password")) {
    return;
  }
  let salt = bcrypt.genSaltSync(10);
  this.password = bcrypt.hashSync(this.password, salt);
});

VendorSchema.methods.comparepassword = function (password) {
  // console.log(password, this.password)
  return bcrypt.compareSync(password, this.password);
};

VendorSchema.methods.generateAccessToken = function () {
  const { getEnv } = require("../utils/envLoader");
  const token = jwt.sign({
    _id: this._id,
    email: this.email,
    vendorName: this.vendorName,
    displayName: this.displayName,
    role: this.role,
    plan: this.plan,
    status: this.status,
    operationalZone: this.operationalZone,
    registeredAddress: this.registeredAddress,
    isDeleted: this.isDeleted
  }, getEnv("JWT_SECRET") || process.env.JWT_SECRET,
    { expiresIn: getEnv("JWT_EXPIRES_IN") || process.env.JWT_EXPIRES_IN });
  return token;
}

VendorSchema.methods.generateRefreshToken = function () {
  const { getEnv } = require("../utils/envLoader");
  const refreshToken = jwt.sign(
    { _id: this._id, role: this.role },
    getEnv("REFRESHTOKEN_SECRET") || process.env.REFRESHTOKEN_SECRET,
    { expiresIn: getEnv("REFRESH_TOKEN_EXPIRES_IN") || process.env.REFRESH_TOKEN_EXPIRES_IN }
  );
  return refreshToken;
}
const Vendor = mongoose.model('Vendor', VendorSchema);

module.exports = Vendor;