/**
 * TASKMATE - Authentication Module
 * ================================
 */

import api from './api.js';
import { $, $$ } from './utils.js';

class AuthManager {
  constructor() {
    this.user = null;
    this.isAuthenticated = false;
    this.loginAttempts = 0;
    this.maxLoginAttempts = 5;
    this.lockoutDuration = 5 * 60 * 1000; // 5 minutes
    this.lockoutUntil = null;
  }

  // Initialize authentication state
  async init() {
    const token = api.getToken();
    console.log('[Auth] init() - Token exists:', !!token);

    if (token) {
      try {
        // Verify token by making a request
        console.log('[Auth] Verifying token...');
        const users = await api.getUsers();
        console.log('[Auth] Token valid, users loaded');
        this.isAuthenticated = true;

        // Get current user from stored data
        const storedUser = localStorage.getItem('current_user');
        if (storedUser) {
          this.user = JSON.parse(storedUser);
        }

        return true;
      } catch (error) {
        // Token invalid
        console.log('[Auth] Token invalid, logging out');
        this.logout();
        return false;
      }
    }

    console.log('[Auth] No token found');
    return false;
  }

  // Login
  async login(username, password) {
    // Check lockout
    if (this.isLockedOut()) {
      const remainingTime = Math.ceil((this.lockoutUntil - Date.now()) / 1000);
      throw new Error(`Zu viele Fehlversuche. Bitte warten Sie ${remainingTime} Sekunden.`);
    }

    try {
      const response = await api.login(username, password);

      this.user = response.user;
      this.isAuthenticated = true;
      this.loginAttempts = 0;

      // Store user data
      localStorage.setItem('current_user', JSON.stringify(response.user));

      // Dispatch login event
      window.dispatchEvent(new CustomEvent('auth:login', {
        detail: { user: this.user }
      }));

      return response;
    } catch (error) {
      this.loginAttempts++;

      if (this.loginAttempts >= this.maxLoginAttempts) {
        this.lockoutUntil = Date.now() + this.lockoutDuration;
      }

      throw error;
    }
  }

  // Logout
  async logout() {
    try {
      if (this.isAuthenticated) {
        await api.logout();
      }
    } catch (error) {
      // Ignore logout errors
    } finally {
      this.user = null;
      this.isAuthenticated = false;

      // Clear stored data
      localStorage.removeItem('current_user');
      localStorage.removeItem('auth_token');

      // Dispatch logout event
      window.dispatchEvent(new CustomEvent('auth:logout'));
    }
  }

  // Change Password
  async changePassword(currentPassword, newPassword) {
    return api.changePassword(currentPassword, newPassword);
  }

  // Get Current User
  getUser() {
    return this.user;
  }

  // Check if logged in
  isLoggedIn() {
    return this.isAuthenticated && this.user !== null;
  }

  // Check lockout status
  isLockedOut() {
    if (!this.lockoutUntil) return false;

    if (Date.now() >= this.lockoutUntil) {
      this.lockoutUntil = null;
      this.loginAttempts = 0;
      return false;
    }

    return true;
  }

  // Get user initials
  getUserInitials() {
    if (!this.user) return '?';
    
    // Verwende das initials Feld direkt
    if (this.user.initials) {
      return this.user.initials.toUpperCase();
    }
    
    // Fallback für alte Daten
    return '??';
  }

  // Get user color
  getUserColor() {
    if (!this.user) return '#888888';
    return this.user.color || '#00D4FF';
  }

  // Update user color
  updateUserColor(color) {
    if (this.user) {
      this.user.color = color;
      // Also update localStorage so color persists after refresh
      localStorage.setItem('current_user', JSON.stringify(this.user));
    }
  }

  // Check if user is admin
  isAdmin() {
    return this.user?.role === 'admin';
  }

  // Check if user has a specific permission
  hasPermission(permission) {
    if (!this.user) return false;
    const permissions = this.user.permissions || [];
    return permissions.includes(permission);
  }

  // Get user role
  getRole() {
    return this.user?.role || 'user';
  }

  // Get user permissions
  getPermissions() {
    return this.user?.permissions || [];
  }
}

// Login Form Handler
class LoginFormHandler {
  constructor(authManager) {
    this.auth = authManager;
    this.form = $('#login-form');
    this.usernameInput = $('#login-username');
    this.passwordInput = $('#login-password');
    this.submitButton = this.form?.querySelector('button[type="submit"]');
    this.errorMessage = $('#login-error');

    this.bindEvents();
  }

  bindEvents() {
    if (!this.form) return;

    this.form.addEventListener('submit', (e) => this.handleSubmit(e));

    // Enter key handling
    this.passwordInput?.addEventListener('keypress', (e) => {
      if (e.key === 'Enter') {
        this.form.dispatchEvent(new Event('submit'));
      }
    });

    // Clear error on input
    [this.usernameInput, this.passwordInput].forEach(input => {
      input?.addEventListener('input', () => this.clearError());
    });
  }

  async handleSubmit(e) {
    e.preventDefault();

    const username = this.usernameInput?.value.trim();
    const password = this.passwordInput?.value;

    if (!username || !password) {
      this.showError('Bitte Benutzername und Passwort eingeben.');
      return;
    }

    this.setLoading(true);
    this.clearError();

    try {
      await this.auth.login(username, password);
      // Success - app will handle the redirect
    } catch (error) {
      this.showError(error.message || 'Anmeldung fehlgeschlagen.');
      this.passwordInput.value = '';
      this.passwordInput.focus();
    } finally {
      this.setLoading(false);
    }
  }

  showError(message) {
    if (this.errorMessage) {
      this.errorMessage.textContent = message;
      this.errorMessage.classList.remove('hidden');
    }
  }

  clearError() {
    if (this.errorMessage) {
      this.errorMessage.textContent = '';
      this.errorMessage.classList.add('hidden');
    }
  }

  setLoading(loading) {
    if (this.submitButton) {
      this.submitButton.disabled = loading;
      this.submitButton.classList.toggle('loading', loading);
    }

    if (this.usernameInput) this.usernameInput.disabled = loading;
    if (this.passwordInput) this.passwordInput.disabled = loading;
  }

  reset() {
    if (this.form) this.form.reset();
    this.clearError();
    this.setLoading(false);
  }
}

// User Menu Handler
class UserMenuHandler {
  constructor(authManager) {
    this.auth = authManager;
    this.userMenu = $('.user-menu');
    this.userAvatar = $('#user-avatar');
    this.userDropdown = $('.user-dropdown');
    this.userName = $('#user-name');
    this.userRole = $('#user-role');
    this.logoutButton = $('#btn-logout');
    this.changePasswordButton = $('#btn-change-password');

    this.isOpen = false;

    this.bindEvents();
  }

  bindEvents() {
    // Toggle dropdown
    this.userAvatar?.addEventListener('click', (e) => {
      e.stopPropagation();
      this.toggle();
    });

    // Close on outside click
    document.addEventListener('click', (e) => {
      if (!this.userMenu?.contains(e.target)) {
        this.close();
      }
    });

    // Logout
    this.logoutButton?.addEventListener('click', () => this.handleLogout());

    // Change password
    this.changePasswordButton?.addEventListener('click', () => {
      this.close();
      window.dispatchEvent(new CustomEvent('modal:open', {
        detail: { modalId: 'change-password-modal' }
      }));
    });

    // Escape key
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && this.isOpen) {
        this.close();
      }
    });
  }

  update() {
    const user = this.auth.getUser();

    if (this.userAvatar) {
      this.userAvatar.textContent = this.auth.getUserInitials();
      this.userAvatar.style.backgroundColor = this.auth.getUserColor();
    }

    if (this.userName) {
      this.userName.textContent = user?.displayName || user?.username || 'Benutzer';
    }

    if (this.userRole) {
      let roleText = 'Benutzer';
      if (user?.role === 'admin') {
        roleText = 'Administrator';
      } else if (user?.permissions?.length > 0) {
        roleText = user.permissions.map(p => p.charAt(0).toUpperCase() + p.slice(1)).join(', ');
      }
      this.userRole.textContent = roleText;
    }
  }

  toggle() {
    if (this.isOpen) {
      this.close();
    } else {
      this.open();
    }
  }

  open() {
    if (this.userDropdown) {
      this.userDropdown.classList.remove('hidden');
      this.isOpen = true;
    }
  }

  close() {
    if (this.userDropdown) {
      this.userDropdown.classList.add('hidden');
      this.isOpen = false;
    }
  }

  async handleLogout() {
    this.close();

    try {
      await this.auth.logout();
    } catch (error) {
      console.error('Logout error:', error);
    }
  }
}

// Session Timer Handler
class SessionTimerHandler {
  constructor(authManager) {
    this.auth = authManager;
    this.timerElement = null;
    this.countdownElement = null;
    this.intervalId = null;
    this.expiresAt = null;
    this.warningThreshold = 60; // Warnung bei 60 Sekunden verbleibend
    this.refreshDebounceTimer = null;
    this.refreshDebounceDelay = 1000; // 1 Sekunde Debounce
    this.isRefreshing = false;
    this.isActive = false; // Nur aktiv wenn eingeloggt und Timer läuft
  }

  init() {
    this.timerElement = $('#session-timer');
    this.countdownElement = $('#session-countdown');

    // Bei Login neu initialisieren
    window.addEventListener('auth:login', () => {
      // Kurze Verzögerung um sicherzustellen, dass Token gespeichert ist
      setTimeout(() => {
        this.updateFromToken();
        this.start();
        this.isActive = true;
      }, 100);
    });

    // Bei Logout stoppen
    window.addEventListener('auth:logout', () => {
      this.isActive = false;
      this.stop();
      this.hide();
    });

    // Bei Interaktionen Session refreshen (mit Debouncing)
    this.bindInteractionEvents();
  }

  // Interaktions-Events binden für Session-Refresh
  bindInteractionEvents() {
    const refreshOnInteraction = (e) => {
      // Nicht refreshen wenn nicht aktiv (nicht eingeloggt oder Timer läuft nicht)
      if (!this.isActive) return;

      // Nicht refreshen bei Klicks auf Login-Formular
      if (e.target.closest('#login-form') || e.target.closest('.login-container')) return;

      // Nur refreshen wenn Token existiert
      if (!localStorage.getItem('auth_token')) return;

      // Debounce: Nur alle X ms refreshen
      if (this.refreshDebounceTimer) {
        clearTimeout(this.refreshDebounceTimer);
      }

      this.refreshDebounceTimer = setTimeout(() => {
        this.refreshSession();
      }, this.refreshDebounceDelay);
    };

    // Click-Events auf dem gesamten Dokument
    document.addEventListener('click', refreshOnInteraction);

    // Keyboard-Events
    document.addEventListener('keydown', refreshOnInteraction);
  }

  // Session beim Server refreshen
  async refreshSession() {
    if (this.isRefreshing) return;

    const token = localStorage.getItem('auth_token');
    if (!token) return;

    this.isRefreshing = true;

    try {
      const response = await fetch('/api/auth/refresh', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`
        }
      });

      if (response.ok) {
        const data = await response.json();
        if (data.token) {
          // Wichtig: api.setToken() verwenden, um den Cache zu aktualisieren
          api.setToken(data.token);
          this.expiresAt = this.parseToken(data.token);
          this.timerElement?.classList.remove('warning', 'critical');

          // CSRF-Token auch aktualisieren
          if (data.csrfToken) {
            api.setCsrfToken(data.csrfToken);
          }
        }
      } else if (response.status === 401) {
        // Token ungültig - aber nur ausloggen wenn kein neuer Login stattfand
        // (Race-Condition: Alter Refresh-Request kann 401 zurückgeben nachdem
        // ein neuer Login erfolgreich war)
        const currentToken = localStorage.getItem('auth_token');
        if (currentToken === token) {
          // Gleicher Token, wirklich ungültig, ausloggen
          console.log('[Auth] Refresh returned 401, logging out');
          this.auth.logout();
        } else {
          // Token hat sich geändert (neuer Login oder bereits ausgeloggt)
          console.log('[Auth] Refresh 401 ignored - token changed (new login occurred)');
        }
      }
    } catch (error) {
      console.error('Session refresh error:', error);
    } finally {
      this.isRefreshing = false;
    }
  }

  // JWT-Token parsen und Ablaufzeit extrahieren
  parseToken(token) {
    if (!token) return null;
    try {
      const payload = token.split('.')[1];
      const decoded = JSON.parse(atob(payload));
      return decoded.exp ? decoded.exp * 1000 : null; // exp ist in Sekunden, wir brauchen ms
    } catch (e) {
      console.error('Token parsing error:', e);
      return null;
    }
  }

  updateFromToken() {
    const token = localStorage.getItem('auth_token');
    this.expiresAt = this.parseToken(token);
  }

  // Beim Seiten-Reload aufrufen
  async initFromExistingSession() {
    const token = localStorage.getItem('auth_token');
    if (!token) {
      this.hide();
      return false;
    }

    // Prüfen ob Token noch gültig ist
    const expiresAt = this.parseToken(token);
    if (!expiresAt || expiresAt <= Date.now()) {
      // Token abgelaufen
      this.hide();
      return false;
    }

    // Timer mit aktuellem Token starten
    this.expiresAt = expiresAt;
    this.isActive = true;
    this.start();

    // Token-Refresh VERZÖGERN um Race-Condition zu vermeiden:
    // Andere Module machen beim Start Requests mit dem aktuellen Token.
    // Ein sofortiger Refresh würde den Token ändern, während Requests noch laufen.
    const remainingTime = expiresAt - Date.now();
    const refreshThreshold = 5 * 60 * 1000; // 5 Minuten

    if (remainingTime < refreshThreshold) {
      // Token läuft bald ab - nach kurzer Verzögerung refreshen
      setTimeout(() => this.refreshSession(), 2000);
    }
    // Sonst: Token ist noch frisch genug, Refresh passiert später durch Interaktion

    return true;
  }

  start() {
    this.stop(); // Bestehenden Timer stoppen

    if (!this.expiresAt) {
      this.hide();
      return;
    }

    this.show();
    this.update(); // Sofort updaten

    // Jede Sekunde aktualisieren
    this.intervalId = setInterval(() => this.update(), 1000);
  }

  stop() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
  }

  update() {
    if (!this.expiresAt || !this.countdownElement) return;

    const now = Date.now();
    const remaining = Math.max(0, this.expiresAt - now);
    const seconds = Math.floor(remaining / 1000);

    // Zeit formatieren
    const minutes = Math.floor(seconds / 60);
    const secs = seconds % 60;
    const timeStr = `${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;

    this.countdownElement.textContent = timeStr;

    // Warnung bei wenig Zeit
    if (seconds <= this.warningThreshold && seconds > 0) {
      this.timerElement?.classList.add('warning');
    } else {
      this.timerElement?.classList.remove('warning');
    }

    // Kritisch bei < 30 Sekunden
    if (seconds <= 30 && seconds > 0) {
      this.timerElement?.classList.add('critical');
    } else {
      this.timerElement?.classList.remove('critical');
    }

    // Session abgelaufen
    if (seconds <= 0) {
      this.stop();
      this.handleExpired();
    }
  }

  handleExpired() {
    // Toast anzeigen
    window.dispatchEvent(new CustomEvent('toast:show', {
      detail: {
        message: 'Sitzung abgelaufen. Bitte erneut anmelden.',
        type: 'warning',
        duration: 5000
      }
    }));

    // Automatisch ausloggen
    this.auth.logout();
  }

  show() {
    this.timerElement?.classList.remove('hidden');
  }

  hide() {
    this.timerElement?.classList.add('hidden');
    if (this.countdownElement) {
      this.countdownElement.textContent = '--:--';
    }
  }

  // Token wurde erneuert (z.B. durch API-Response mit X-New-Token)
  refreshToken(newToken) {
    if (newToken) {
      // api.setToken() wird bereits in api.js aufgerufen, hier nur Timer aktualisieren
      this.expiresAt = this.parseToken(newToken);
      this.timerElement?.classList.remove('warning', 'critical');
    }
  }
}

// Change Password Modal Handler
class ChangePasswordHandler {
  constructor(authManager) {
    this.auth = authManager;
    this.modal = $('#change-password-modal');
    this.form = $('#change-password-form');
    this.currentPassword = $('#current-password');
    this.newPassword = $('#new-password');
    this.confirmPassword = $('#confirm-password');
    this.errorMessage = this.modal?.querySelector('.error-message');
    this.submitButton = this.form?.querySelector('button[type="submit"]');

    this.bindEvents();
  }

  bindEvents() {
    this.form?.addEventListener('submit', (e) => this.handleSubmit(e));

    // Password strength indicator
    this.newPassword?.addEventListener('input', () => {
      this.updatePasswordStrength();
    });

    // Confirm password validation
    this.confirmPassword?.addEventListener('input', () => {
      this.validateConfirmPassword();
    });
  }

  async handleSubmit(e) {
    e.preventDefault();

    const currentPassword = this.currentPassword?.value;
    const newPassword = this.newPassword?.value;
    const confirmPassword = this.confirmPassword?.value;

    // Validation
    if (!currentPassword || !newPassword || !confirmPassword) {
      this.showError('Bitte alle Felder ausfüllen.');
      return;
    }

    if (newPassword.length < 8) {
      this.showError('Das neue Passwort muss mindestens 8 Zeichen lang sein.');
      return;
    }

    if (newPassword !== confirmPassword) {
      this.showError('Die Passwörter stimmen nicht überein.');
      return;
    }

    this.setLoading(true);
    this.clearError();

    try {
      await this.auth.changePassword(currentPassword, newPassword);

      // Success
      this.reset();
      this.closeModal();

      window.dispatchEvent(new CustomEvent('toast:show', {
        detail: {
          message: 'Passwort erfolgreich geändert.',
          type: 'success'
        }
      }));
    } catch (error) {
      this.showError(error.message || 'Fehler beim Ändern des Passworts.');
    } finally {
      this.setLoading(false);
    }
  }

  updatePasswordStrength() {
    const password = this.newPassword?.value || '';
    const strengthIndicator = this.modal?.querySelector('.password-strength');

    if (!strengthIndicator) return;

    let strength = 0;
    if (password.length >= 8) strength++;
    if (password.length >= 12) strength++;
    if (/[A-Z]/.test(password)) strength++;
    if (/[a-z]/.test(password)) strength++;
    if (/[0-9]/.test(password)) strength++;
    if (/[^A-Za-z0-9]/.test(password)) strength++;

    const levels = ['weak', 'fair', 'good', 'strong'];
    const level = Math.min(Math.floor(strength / 1.5), 3);

    strengthIndicator.className = `password-strength ${levels[level]}`;
    strengthIndicator.dataset.strength = levels[level];
  }

  validateConfirmPassword() {
    const newPassword = this.newPassword?.value;
    const confirmPassword = this.confirmPassword?.value;

    if (confirmPassword && newPassword !== confirmPassword) {
      this.confirmPassword.setCustomValidity('Passwörter stimmen nicht überein');
    } else {
      this.confirmPassword.setCustomValidity('');
    }
  }

  showError(message) {
    if (this.errorMessage) {
      this.errorMessage.textContent = message;
      this.errorMessage.classList.remove('hidden');
    }
  }

  clearError() {
    if (this.errorMessage) {
      this.errorMessage.textContent = '';
      this.errorMessage.classList.add('hidden');
    }
  }

  setLoading(loading) {
    if (this.submitButton) {
      this.submitButton.disabled = loading;
      this.submitButton.classList.toggle('loading', loading);
    }
  }

  reset() {
    if (this.form) this.form.reset();
    this.clearError();
    this.setLoading(false);
  }

  closeModal() {
    window.dispatchEvent(new CustomEvent('modal:close', {
      detail: { modalId: 'change-password-modal' }
    }));
  }
}

// Create singleton instances
const authManager = new AuthManager();
let loginFormHandler = null;
let userMenuHandler = null;
let changePasswordHandler = null;
let sessionTimerHandler = null;

// Initialize handlers when DOM is ready
async function initAuthHandlers() {
  loginFormHandler = new LoginFormHandler(authManager);
  userMenuHandler = new UserMenuHandler(authManager);
  changePasswordHandler = new ChangePasswordHandler(authManager);
  sessionTimerHandler = new SessionTimerHandler(authManager);
  sessionTimerHandler.init();

  // Bei bestehendem Token: Session refreshen und Timer starten
  const token = localStorage.getItem('auth_token');
  if (token) {
    await sessionTimerHandler.initFromExistingSession();
  }
}

// Listen for DOM ready
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initAuthHandlers);
} else {
  initAuthHandlers();
}

// Listen for login event to update UI
window.addEventListener('auth:login', () => {
  userMenuHandler?.update();
});

// Listen for token refresh event to update session timer
window.addEventListener('auth:token-refreshed', (e) => {
  sessionTimerHandler?.refreshToken(e.detail?.token);
});

export {
  authManager,
  loginFormHandler,
  userMenuHandler,
  changePasswordHandler,
  sessionTimerHandler
};

export default authManager;
