const BaseModel = require('./BaseModel');
const mongoose = require('mongoose');

const taxSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, 'Tax name is required'],
    trim: true,
    maxlength: [100, 'Tax name cannot exceed 100 characters']
  },
  percentage: {
    type: Number,
    required: [true, 'Tax percentage is required'],
    min: [0, 'Tax percentage cannot be negative'],
    max: [100, 'Tax percentage cannot exceed 100%'],
    validate: {
      validator: function(v) {
        return Number.isFinite(v) && v >= 0 && v <= 100;
      },
      message: 'Tax percentage must be a valid number between 0 and 100'
    }
  },
  status: {
    type: Boolean,
    default: true
  }
}, {
  timestamps: true,
  toJSON: { virtuals: true },
  toObject: { virtuals: true }
});

// Indexes for better performance
taxSchema.index({ name: 1 });
taxSchema.index({ percentage: 1 });
taxSchema.index({ status: 1 });
taxSchema.index({ name: 'text' }); // Text search

// Virtual for getting items using this tax
taxSchema.virtual('items', {
  ref: 'Item',
  localField: '_id',
  foreignField: 'taxId'
});

class Tax extends BaseModel {
  static get schema() {
    return taxSchema;
  }

  /**
   * Initialize the Tax model
   */
  static init() {
    const model = super.init();
    
    // Ensure text index is created
    if (model.collection) {
      model.collection.createIndex({
        name: 'text'
      }).catch(err => {
        console.warn('Failed to create text index for Tax:', err.message);
      });
    }
    
    return model;
  }

  /**
   * Get all taxes with pagination and search
   */
  static async findAllActive(options = {}) {
    const { page = 1, limit = 10, search } = options;

    let query = { status: true };

    // Add search filter
    if (search) {
      query.$text = { $search: search };
    }

    return this.paginate(query, {
      page,
      limit,
      sort: search ? { score: { $meta: 'textScore' } } : { percentage: 1 },
      select: 'name percentage status createdAt updatedAt',
      lean: true
    });
  }

  /**
   * Get tax by ID with associated items count
   */
  static async findByIdWithDetails(id) {
    return this.aggregate([
      {
        $match: {
          _id: new mongoose.Types.ObjectId(id)
        }
      },
      {
        $lookup: {
          from: 'items',
          let: { taxId: '$_id' },
          pipeline: [
            {
              $match: {
                $expr: {
                  $and: [
                    { $eq: ['$taxId', '$$taxId'] },
                    { $eq: ['$status', true] }
                  ]
                }
              }
            },
            {
              $count: 'count'
            }
          ],
          as: 'itemStats'
        }
      },
      {
        $addFields: {
          itemCount: { $arrayElemAt: ['$itemStats.count', 0] },
          id: '$_id'
        }
      },
      {
        $project: {
          itemStats: 0,
          __v: 0
        }
      }
    ]).then(results => results[0] || null);
  }

  /**
   * Create new tax with validation
   */
  static async createTax(data) {
    const { name, percentage } = data;

    // Check if tax name already exists
    const existingTax = await this.findOne({
      name: new RegExp(`^${name.trim()}$`, 'i')
    });

    if (existingTax) {
      throw new Error('Tax name already exists');
    }

    // Check if percentage already exists
    const existingPercentage = await this.findOne({
      percentage: percentage
    });

    if (existingPercentage) {
      throw new Error('Tax with this percentage already exists');
    }

    return this.create({
      name: name.trim(),
      percentage: parseFloat(percentage)
    });
  }

  /**
   * Update tax with validation
   */
  static async updateTax(id, updateData) {
    const { name, percentage, status } = updateData;

    // Check if new tax name conflicts with existing tax
    if (name) {
      const existingTax = await this.findOne({
        name: new RegExp(`^${name.trim()}$`, 'i'),
        _id: { $ne: id }
      });

      if (existingTax) {
        throw new Error('Tax name already exists');
      }
    }

    // Check if new percentage conflicts with existing tax
    if (percentage !== undefined) {
      const existingPercentage = await this.findOne({
        percentage: parseFloat(percentage),
        _id: { $ne: id }
      });

      if (existingPercentage) {
        throw new Error('Tax with this percentage already exists');
      }
    }

    const updateFields = {};
    if (name !== undefined) updateFields.name = name.trim();
    if (percentage !== undefined) updateFields.percentage = parseFloat(percentage);
    if (status !== undefined) updateFields.status = status;

    return this.update(id, updateFields);
  }

  /**
   * Permanently delete tax (hard delete)
   */
  static async deleteTax(id) {
    return this.delete(id);
  }

  /**
   * Get active taxes for dropdown/selection
   */
  static async getActiveTaxes() {
    try {
      return await this.model
        .find({ status: true })
        .select('name percentage')
        .sort({ percentage: 1 })
        .lean();
    } catch (error) {
      console.error('Error in getActiveTaxes:', error);
      throw error;
    }
  }

  /**
   * Get tax percentage by ID
   */
  static async getTaxPercentage(taxId) {
    const tax = await this.findById(taxId).select('percentage status').lean();
    return (tax && tax.status) ? tax.percentage : 0;
  }

  /**
   * Toggle tax status
   */
  static async toggleTaxStatus(id) {
    const tax = await this.findById(id);
    if (!tax) {
      throw new Error('Tax not found');
    }

    tax.status = !tax.status;
    return tax.save();
  }

  /**
   * Get tax statistics
   */
  static async getStatistics() {
    return this.aggregate([
      {
        $group: {
          _id: null,
          totalTaxes: { $sum: 1 },
          activeTaxes: {
            $sum: {
              $cond: [{ $eq: ['$status', true] }, 1, 0]
            }
          },
          inactiveTaxes: {
            $sum: {
              $cond: [{ $eq: ['$status', false] }, 1, 0]
            }
          },
          averagePercentage: { $avg: '$percentage' },
          minPercentage: { $min: '$percentage' },
          maxPercentage: { $max: '$percentage' }
        }
      }
    ]).then(results => results[0] || {
      totalTaxes: 0,
      activeTaxes: 0,
      inactiveTaxes: 0,
      averagePercentage: 0,
      minPercentage: 0,
      maxPercentage: 0
    });
  }

  /**
   * Search taxes with text search
   */
  static async searchTaxes(query, page = 1, limit = 10) {
    const searchQuery = {
      $text: { $search: query }
    };

    return this.paginate(searchQuery, {
      page,
      limit,
      sort: { score: { $meta: 'textScore' } },
      select: 'name percentage status createdAt updatedAt',
      lean: true
    });
  }
}

module.exports = Tax;
