/**
 * 数据库模型基类
 * @file BaseModel.js
 * @description 提供所有模型的基础功能和通用方法
 */
const { Model, DataTypes } = require('sequelize');
const queryOptimizer = require('../utils/query-optimizer');

class BaseModel extends Model {
  /**
   * 初始化模型
   * @param {Object} sequelize Sequelize实例
   * @param {Object} attributes 模型属性
   * @param {Object} options 模型选项
   */
  static init(attributes, options = {}) {
    // 确保options中包含sequelize实例
    if (!options.sequelize) {
      throw new Error('必须提供sequelize实例');
    }

    // 默认配置
    const defaultOptions = {
      // 使用下划线命名法
      underscored: true,
      // 默认时间戳字段
      timestamps: true,
      createdAt: 'created_at',
      updatedAt: 'updated_at',
      // 默认不使用软删除
      paranoid: false,
      // 字符集和排序规则
      charset: 'utf8mb4',
      collate: 'utf8mb4_unicode_ci'
    };

    // 合并选项
    const mergedOptions = { ...defaultOptions, ...options };

    // 调用父类的init方法
    return super.init(attributes, mergedOptions);
  }

  /**
   * 分页查询
   * @param {Object} options 查询选项
   * @param {Number} page 页码
   * @param {Number} pageSize 每页记录数
   * @returns {Promise<Object>} 分页结果
   */
  static async paginate(options = {}, page = 1, pageSize = 10) {
    // 确保页码和每页记录数为正整数
    page = Math.max(1, parseInt(page));
    pageSize = Math.max(1, parseInt(pageSize));

    // 计算偏移量
    const offset = (page - 1) * pageSize;

    // 合并分页参数
    const paginateOptions = {
      ...options,
      limit: pageSize,
      offset
    };

    // 执行查询
    const { count, rows } = await this.findAndCountAll(paginateOptions);

    // 计算总页数
    const totalPages = Math.ceil(count / pageSize);

    // 返回分页结果
    return {
      data: rows,
      pagination: {
        total: count,
        page,
        pageSize,
        totalPages,
        hasMore: page < totalPages
      }
    };
  }

  /**
   * 批量创建或更新记录
   * @param {Array} records 记录数组
   * @param {Array|String} uniqueFields 唯一字段或字段数组
   * @returns {Promise<Array>} 创建或更新的记录
   */
  static async bulkUpsert(records, uniqueFields) {
    if (!Array.isArray(records) || records.length === 0) {
      return [];
    }

    // 确保uniqueFields是数组
    const fields = Array.isArray(uniqueFields) ? uniqueFields : [uniqueFields];

    // 获取所有字段
    const allFields = Object.keys(this.rawAttributes);

    // 批量创建或更新
    const result = await this.bulkCreate(records, {
      updateOnDuplicate: allFields.filter(field => {
        // 排除主键和时间戳字段
        return (
          field !== 'id' &&
          field !== 'created_at' &&
          field !== 'updated_at'
        );
      }),
      // 返回创建或更新后的记录
      returning: true
    });

    return result;
  }

  /**
   * 执行原始SQL查询
   * @param {String} sql SQL语句
   * @param {Object} replacements 替换参数
   * @param {String} type 查询类型
   * @returns {Promise<Array|Object>} 查询结果
   */
  static async rawQuery(sql, replacements = {}, type = 'SELECT') {
    const sequelize = this.sequelize;
    const QueryTypes = sequelize.QueryTypes;

    // 执行查询前分析查询性能
    if (process.env.NODE_ENV === 'development') {
      try {
        const explainResult = await queryOptimizer.explainQuery(sql, replacements);
        console.log('查询分析结果:', explainResult);
      } catch (error) {
        console.warn('查询分析失败:', error.message);
      }
    }

    // 执行查询
    return sequelize.query(sql, {
      replacements,
      type: QueryTypes[type],
      model: this,
      mapToModel: type === 'SELECT'
    });
  }

  /**
   * 获取模型的表信息
   * @returns {Promise<Object>} 表信息
   */
  static async getTableInfo() {
    const tableName = this.getTableName();
    return queryOptimizer.getTableInfo(tableName);
  }

  /**
   * 获取模型的索引信息
   * @returns {Promise<Array>} 索引信息
   */
  static async getIndexes() {
    const tableName = this.getTableName();
    return queryOptimizer.getTableIndexes(tableName);
  }

  /**
   * 分析表结构
   * @returns {Promise<Object>} 分析结果
   */
  static async analyzeTable() {
    const tableName = this.getTableName();
    return queryOptimizer.analyzeTable(tableName);
  }

  /**
   * 优化表
   * @returns {Promise<Object>} 优化结果
   */
  static async optimizeTable() {
    const tableName = this.getTableName();
    return queryOptimizer.optimizeTable(tableName);
  }
}

module.exports = BaseModel;