const { DataTypes } = require('sequelize');
const bcrypt = require('bcryptjs');
const config = require('../config');

module.exports = (sequelize) => {
  const Admin = sequelize.define('Admin', {
    id: {
      type: DataTypes.BIGINT.UNSIGNED,
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
    },
    role: {
      type: DataTypes.ENUM('admin', 'superadmin'),
      defaultValue: 'admin',
    },
    name: {
      type: DataTypes.STRING(50),
      field: 'first_name',
    },

    email: {
      type: DataTypes.STRING(255),
      allowNull: false,
      unique: true,
      validate: {
        isEmail: true,
      },
    },

    password: {
      type: DataTypes.STRING(255),
      allowNull: false,
    },
    timezone: {
      type: DataTypes.STRING(50),
      defaultValue: 'UTC',
    },

    dateFormat: {
      type: DataTypes.STRING(20),
      defaultValue: 'MM/DD/YYYY',
      field: 'date_format',
    },

    // Account Status
    status: {
      type: DataTypes.ENUM('active', 'inactive', 'suspended', 'pending'),
      defaultValue: 'pending',
    },

    loginNotifications: {
      type: DataTypes.BOOLEAN,
      defaultValue: true,
      field: 'login_notifications',
    },

    // Password Reset
    passwordResetToken: {
      type: DataTypes.STRING(255),
      field: 'password_reset_token',
    },
    passwordResetExpires: {
      type: DataTypes.DATE,
      field: 'password_reset_expires',
    },
    passwordChangedAt: {
      type: DataTypes.DATE,
      field: 'password_changed_at',
    },

    twoFactorEnabled: {
      type: DataTypes.BOOLEAN,
      defaultValue: false,
      field: 'two_factor_enabled',
    },
    twoFactorSecret: {
      type: DataTypes.STRING(255),
      field: 'two_factor_secret',
    },
    twoFactorTempSecret: {
      type: DataTypes.STRING(255),
      field: 'two_factor_temp_secret',
    },

    twoFactorMethod: {
      type: DataTypes.ENUM('authenticator', 'sms', 'email'),
      defaultValue: 'authenticator',
      field: 'two_factor_method',
    },
    backupCodes: {
      type: DataTypes.JSON,
      field: 'backup_codes',
    },

    // Login Tracking
    lastLogin: {
      type: DataTypes.DATE,
      field: 'last_login',
    },
    lastLoginIp: {
      type: DataTypes.STRING(45),
      field: 'last_login_ip',
    },
    lastLoginDevice: {
      type: DataTypes.STRING(255),
      field: 'last_login_device',
    },
    loginAttempts: {
      type: DataTypes.INTEGER,
      defaultValue: 0,
      field: 'login_attempts',
    },
    lockUntil: {
      type: DataTypes.DATE,
      field: 'lock_until',
    },

    // Quiet Hours
    quietHours: {
      type: DataTypes.JSON,
      defaultValue: {
        enabled: false,
        start: '22:00',
        end: '07:00',
      },
      field: 'quiet_hours',
    },

    // Metadata
    metadata: {
      type: DataTypes.JSON,
      defaultValue: {},
    },
  }, {
    tableName: 'admins',
    timestamps: true,
    underscored: true,
    indexes: [
      { fields: ['email'] },
      { fields: ['status'] },

    ],
  });

  // Hooks
  Admin.beforeCreate(async (user) => {
    if (user.password) {
      user.password = await bcrypt.hash(user.password, config.bcryptSaltRounds);
    }
  });

  Admin.beforeUpdate(async (user) => {
    if (user.changed('password')) {
      user.password = await bcrypt.hash(user.password, config.bcryptSaltRounds);
      user.passwordChangedAt = new Date();
    }
  });

  // Instance Methods
  Admin.prototype.comparePassword = async function (candidatePassword) {
    return bcrypt.compare(candidatePassword, this.password);
  };

  Admin.prototype.changedPasswordAfter = function (jwtTimestamp) {
    if (this.passwordChangedAt) {
      const changedTimestamp = parseInt(this.passwordChangedAt.getTime() / 1000, 10);
      return jwtTimestamp < changedTimestamp;
    }
    return false;
  };

  Admin.prototype.isLocked = function () {
    return !!(this.lockUntil && this.lockUntil > new Date());
  };

  Admin.prototype.incrementLoginAttempts = async function () {
    if (this.lockUntil && this.lockUntil < new Date()) {
      await this.update({ loginAttempts: 1, lockUntil: null });
      return;
    }

    const updates = { loginAttempts: this.loginAttempts + 1 };
    if (this.loginAttempts + 1 >= 5) {
      updates.lockUntil = new Date(Date.now() + 2 * 60 * 60 * 1000);
    }
    await this.update(updates);
  };

  Admin.prototype.getVerificationLimits = function () {
    const limits = config.verificationLimits;
    switch (this.kycStatus) {
      case 'level4': return limits.level4;
      case 'level3': return limits.level3;
      case 'level2': return limits.level2;
      case 'level1': return limits.level1;
      default: return { daily: 0, monthly: 0 };
    }
  };

  Admin.prototype.toJSON = function () {
    const values = { ...this.get() };
    delete values.password;
    delete values.passwordResetToken;
    return values;
  };

  // Class Methods
  Admin.findByCredentials = async function (email, password) {
    const user = await this.findOne({ where: { email } });
    if (!user) return null;

    const isMatch = await user.comparePassword(password);
    if (!isMatch) return null;

    return user;
  };

  return Admin;
};
