import { DataTypes, Model } from 'sequelize';
import crypto from 'crypto';
import sequelize from '../database.js';
import Club from './Club.js';
import { encryptData, decryptData } from '../utils/encrypt.js';

const Member = sequelize.define('Member', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
    allowNull: false
  },
  hashedId: {
    type: DataTypes.STRING,
    unique: true,
    allowNull: false,
    defaultValue() {
      return crypto.randomBytes(64).toString('hex');
    }
  },
  firstName: {
    type: DataTypes.STRING,
    allowNull: false,
    set(value) {
      const encryptedValue = encryptData(value);
      this.setDataValue('firstName', encryptedValue);
    },
    get() {
      const encryptedValue = this.getDataValue('firstName');
      return decryptData(encryptedValue);
    }
  },
  lastName: {
    type: DataTypes.STRING,
    allowNull: false,
    set(value) {
      const encryptedValue = encryptData(value);
      this.setDataValue('lastName', encryptedValue);
    },
    get() {
      const encryptedValue = this.getDataValue('lastName');
      return decryptData(encryptedValue);
    }
  },
  birthDate: {
    type: DataTypes.STRING, 
    allowNull: true,
    set(value) {
      const encryptedValue = encryptData(value || '');
      this.setDataValue('birthDate', encryptedValue);
    },
    get() {
      const encryptedValue = this.getDataValue('birthDate');
      if (!encryptedValue) return null;
      return decryptData(encryptedValue);
    }
  },
  phone: {
    type: DataTypes.STRING,
    allowNull: false,
    set(value) {
      const encryptedValue = encryptData(value);
      this.setDataValue('phone', encryptedValue);
    },
    get() {
      const encryptedValue = this.getDataValue('phone');
      return decryptData(encryptedValue);
    }
  },
  street: {
    type: DataTypes.STRING,
    allowNull: false,
    set(value) {
      const encryptedValue = encryptData(value);
      this.setDataValue('street', encryptedValue);
    },
    get() {
      const encryptedValue = this.getDataValue('street');
      return decryptData(encryptedValue);
    }
  },
  city: {
    type: DataTypes.STRING,
    allowNull: false,
    set(value) {
      const encryptedValue = encryptData(value);
      this.setDataValue('city', encryptedValue);
    },
    get() {
      const encryptedValue = this.getDataValue('city');
      return decryptData(encryptedValue);
    }
  },
  postalCode: {
    type: DataTypes.STRING,
    allowNull: true,
    set(value) {
      const encryptedValue = encryptData(value || '');
      this.setDataValue('postalCode', encryptedValue);
    },
    get() {
      const encryptedValue = this.getDataValue('postalCode');
      if (!encryptedValue) return null;
      return decryptData(encryptedValue);
    },
    field: 'postal_code',
    comment: 'Postal code (PLZ)'
  },
  email: {
    type: DataTypes.STRING,
    allowNull: false,
    set(value) {
      const encryptedValue = encryptData(value);
      this.setDataValue('email', encryptedValue);
    }, 
    get() {
      const encryptedValue = this.getDataValue('email');
      return decryptData(encryptedValue);
    }
  },
  clubId: {
    type: DataTypes.INTEGER,
    allowNull: false,
  },
  membershipStatus: {
    type: DataTypes.STRING,
    allowNull: false,
    defaultValue: 'active',
    field: 'membership_status',
  },
  membershipType: {
    type: DataTypes.STRING,
    allowNull: false,
    defaultValue: 'regular',
    field: 'membership_type',
  },
  joinedOn: {
    type: DataTypes.DATEONLY,
    allowNull: true,
    field: 'joined_on',
  },
  leftOn: {
    type: DataTypes.DATEONLY,
    allowNull: true,
    field: 'left_on',
  },
  contributionGroupCode: {
    type: DataTypes.STRING,
    allowNull: true,
    field: 'contribution_group_code',
  },
  needsSepaMandate: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    defaultValue: false,
    field: 'needs_sepa_mandate',
  },
  sepaMandateReference: {
    type: DataTypes.STRING,
    allowNull: true,
    field: 'sepa_mandate_reference',
  },
  isArchived: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    defaultValue: false,
    field: 'is_archived',
  },
  archivedAt: {
    type: DataTypes.DATE,
    allowNull: true,
    field: 'archived_at',
  },
  archivedReason: {
    type: DataTypes.TEXT,
    allowNull: true,
    field: 'archived_reason',
  },
  active: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    default: true,
  },
  testMembership: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    default: false,
  },
  picsInInternetAllowed: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    default: false,
  },
  gender: {
    type: DataTypes.ENUM('male','female','diverse','unknown'),
    allowNull: true,
    defaultValue: 'unknown'
  },
  ttr: {
    type: DataTypes.INTEGER,
    allowNull: true,
    defaultValue: null
  },
  qttr: {
    type: DataTypes.INTEGER,
    allowNull: true,
    defaultValue: null
  },
  memberFormHandedOver: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    defaultValue: false,
    field: 'member_form_handed_over',
    comment: 'Mitgliedsformular ausgehändigt'
  },
  adultReleaseApproved: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    defaultValue: false,
    field: 'adult_release_approved',
    comment: 'Jugendspieler mit Freigabe fuer Erwachsene'
  },
  adultReserveApproved: {
    type: DataTypes.BOOLEAN,
    allowNull: false,
    defaultValue: false,
    field: 'adult_reserve_approved',
    comment: 'Jugendspieler als Ersatz bei Erwachsenen zugelassen'
  },
  myTischtennisPlayerId: {
    type: DataTypes.STRING,
    allowNull: true,
    comment: 'Player ID from myTischtennis (e.g. NU2705037)',
    field: 'my_tischtennis_player_id'
  },
  myTischtennisHistoryPlayerId: {
    type: DataTypes.STRING,
    allowNull: true,
    comment: 'TTR history player ID from myTischtennis (e.g. P14EC4981D)',
    field: 'my_tischtennis_history_player_id'
  }
}, {
  underscored: true,
  sequelize,
  modelName: 'Member',
  tableName: 'member',
  timestamps: true,

  hooks: {
    afterCreate: (member) => {
      member.hashedId = crypto.createHash('sha256').update(String(member.id)).digest('hex');
      member.save();
    },
  }
});

Member.belongsTo(Club, { as: 'club', foreignKey: 'clubId', constraints: false });
Club.hasMany(Member, { as: 'members', foreignKey: 'clubId', constraints: false });

export default Member;
