const { Sequelize } = require('sequelize');

/**
 * Sequelize-Datenbank-Konfiguration
 */
class Database {
  constructor() {
    this.sequelize = null;
  }

  /**
   * Sequelize-Instanz initialisieren
   */
  async initialize() {
    try {
      // Sequelize-Instanz mit .env-Konfiguration erstellen
      this.sequelize = new Sequelize(
        process.env.DB_NAME || 'stechuhr2',
        process.env.DB_USER || 'root',
        process.env.DB_PASSWORD || '',
        {
          host: process.env.DB_HOST || 'localhost',
          port: parseInt(process.env.DB_PORT) || 3306,
          dialect: 'mysql',
          
          // Timezone-Konfiguration
          // Die DB speichert lokale Zeit ohne TZ-Info
          // Worklog.tstamp ist als STRING definiert, daher erfolgt KEINE automatische TZ-Konvertierung
          timezone: '+00:00', // Keine Konvertierung für andere DATE-Felder
          
          // Logging
          logging: process.env.DB_LOGGING === 'true' ? console.log : false,
          
          // Connection Pool
          pool: {
            max: parseInt(process.env.DB_POOL_MAX) || 10,
            min: parseInt(process.env.DB_POOL_MIN) || 0,
            acquire: 30000,
            idle: 10000
          },
          
          // Optionen
          define: {
            timestamps: false, // Wir verwenden eigene timestamp-Felder
            underscored: true,  // snake_case in DB
            freezeTableName: true // Tabellennamen nicht pluralisieren
          }
        }
      );

      // Verbindung testen
      await this.sequelize.authenticate();
      console.log('✅ Sequelize: MySQL-Datenbankverbindung hergestellt');
      
      // Models initialisieren
      await this.initializeModels();
      
      return this.sequelize;
    } catch (error) {
      console.error('❌ Sequelize: Fehler bei der Datenbankverbindung:', error.message);
      console.error('Details:', error);
      throw error;
    }
  }

  /**
   * Models laden und Assoziationen definieren
   */
  async initializeModels() {
    // Models importieren
    const User = require('../models/User');
    const Worklog = require('../models/Worklog');
    const AuthInfo = require('../models/AuthInfo');
    const AuthToken = require('../models/AuthToken');
    const AuthIdentity = require('../models/AuthIdentity');
    const State = require('../models/State');
    const WeeklyWorktime = require('../models/WeeklyWorktime');
    const Holiday = require('../models/Holiday');
    const HolidayState = require('../models/HolidayState');
    const Vacation = require('../models/Vacation');
    const Sick = require('../models/Sick');
    const SickType = require('../models/SickType');
    const Timefix = require('../models/Timefix');
    const Timewish = require('../models/Timewish');
    const Invitation = require('../models/Invitation');
    const Watcher = require('../models/Watcher');

    // Models mit Sequelize-Instanz initialisieren
    User.initialize(this.sequelize);
    Worklog.initialize(this.sequelize);
    AuthInfo.initialize(this.sequelize);
    AuthToken.initialize(this.sequelize);
    AuthIdentity.initialize(this.sequelize);
    State.initialize(this.sequelize);
    WeeklyWorktime.initialize(this.sequelize);
    Holiday.initialize(this.sequelize);
    HolidayState.initialize(this.sequelize);
    Vacation.initialize(this.sequelize);
    Sick.initialize(this.sequelize);
    SickType.initialize(this.sequelize);
    Timefix.initialize(this.sequelize);
    Timewish.initialize(this.sequelize);
    Invitation.initialize(this.sequelize);
    Watcher.initialize(this.sequelize);

    // Assoziationen definieren
    this.defineAssociations();

    console.log('✅ Sequelize: Models initialisiert');
  }

  /**
   * Model-Assoziationen definieren
   */
  defineAssociations() {
    const { User, Worklog, AuthInfo, AuthToken, AuthIdentity, State, WeeklyWorktime, Holiday, HolidayState, Vacation, Sick, SickType, Timefix, Timewish, Invitation, Watcher } = this.sequelize.models;

    // User Assoziationen
    User.hasMany(Worklog, { foreignKey: 'user_id', as: 'worklogs' });
    User.hasOne(AuthInfo, { foreignKey: 'user_id', as: 'authInfo' });
    User.belongsTo(State, { foreignKey: 'state_id', as: 'state' });
    User.hasMany(WeeklyWorktime, { foreignKey: 'user_id', as: 'weeklyWorktimes' });
    User.hasMany(Vacation, { foreignKey: 'user_id', as: 'vacations' });
    User.hasMany(Sick, { foreignKey: 'user_id', as: 'sickLeaves' });

    // Worklog Assoziationen
    Worklog.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
    Worklog.belongsTo(Worklog, { foreignKey: 'relatedTo_id', as: 'relatedTo' });
    Worklog.hasOne(Worklog, { foreignKey: 'relatedTo_id', as: 'clockOut' });
    Worklog.hasMany(Timefix, { foreignKey: 'worklog_id', as: 'timefixes' });

    // Timefix Assoziationen
    Timefix.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
    Timefix.belongsTo(Worklog, { foreignKey: 'worklog_id', as: 'worklog' });

    // AuthInfo Assoziationen
    AuthInfo.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
    AuthInfo.hasMany(AuthToken, { foreignKey: 'auth_info_id', as: 'tokens' });
    AuthInfo.hasMany(AuthIdentity, { foreignKey: 'auth_info_id', as: 'identities' });

    // AuthToken Assoziationen
    AuthToken.belongsTo(AuthInfo, { foreignKey: 'auth_info_id', as: 'authInfo' });

    // AuthIdentity Assoziationen
    AuthIdentity.belongsTo(AuthInfo, { foreignKey: 'auth_info_id', as: 'authInfo' });

    // WeeklyWorktime Assoziationen
    WeeklyWorktime.belongsTo(User, { foreignKey: 'user_id', as: 'user' });

    // Vacation Assoziationen
    Vacation.belongsTo(User, { foreignKey: 'user_id', as: 'user' });

    // Sick Assoziationen
    Sick.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
    Sick.belongsTo(SickType, { foreignKey: 'sick_type_id', as: 'sickType' });

    // SickType Assoziationen
    SickType.hasMany(Sick, { foreignKey: 'sick_type_id', as: 'sickLeaves' });
    
    // Holiday Assoziationen (Many-to-Many mit State)
    Holiday.belongsToMany(State, {
      through: HolidayState,
      foreignKey: 'holiday_id',
      otherKey: 'state_id',
      as: 'states'
    });
    
    State.belongsToMany(Holiday, {
      through: HolidayState,
      foreignKey: 'state_id',
      otherKey: 'holiday_id',
      as: 'holidays'
    });
    
    // HolidayState Assoziationen
    HolidayState.belongsTo(Holiday, { foreignKey: 'holiday_id', as: 'holiday' });
    HolidayState.belongsTo(State, { foreignKey: 'state_id', as: 'state' });
    
    // Timewish Assoziationen
    Timewish.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
    User.hasMany(Timewish, { foreignKey: 'user_id', as: 'timewishes' });
    
    // Invitation Assoziationen
    Invitation.belongsTo(User, { foreignKey: 'inviter_user_id', as: 'inviter' });
    User.hasMany(Invitation, { foreignKey: 'inviter_user_id', as: 'invitations' });
    
    // Watcher Assoziationen
    Watcher.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
    User.hasMany(Watcher, { foreignKey: 'user_id', as: 'watchers' });
  }

  /**
   * Sequelize-Instanz zurückgeben
   */
  getSequelize() {
    if (!this.sequelize) {
      throw new Error('Sequelize nicht initialisiert. Rufen Sie zuerst initialize() auf.');
    }
    return this.sequelize;
  }

  /**
   * Modelle zurückgeben
   */
  getModels() {
    if (!this.sequelize) {
      throw new Error('Sequelize nicht initialisiert. Rufen Sie zuerst initialize() auf.');
    }
    return this.sequelize.models;
  }

  /**
   * Verbindung schließen
   */
  async close() {
    if (this.sequelize) {
      await this.sequelize.close();
      console.log('🔒 Sequelize: Datenbankverbindung geschlossen');
    }
  }

  /**
   * Datenbank synchronisieren (nur für Entwicklung!)
   * @param {Object} options - Sync-Optionen
   */
  async sync(options = {}) {
    if (this.sequelize) {
      await this.sequelize.sync(options);
      console.log('🔄 Sequelize: Datenbank synchronisiert');
    }
  }
}

// Singleton-Instanz exportieren
module.exports = new Database();
