import { createStore } from 'vuex';
import dialogs from './modules/dialogs';
import loadMenu from '../utils/menuLoader.js';
import router from '../router';
import apiClient from '../utils/axios.js';
import { io } from 'socket.io-client';

const store = createStore({
  state: {
    isLoggedIn: localStorage.getItem('isLoggedIn') === 'true',
    connectionStatus: 'disconnected', // 'connected', 'connecting', 'disconnected', 'error'
    daemonConnectionStatus: 'disconnected', // 'connected', 'connecting', 'disconnected', 'error'
    user: JSON.parse(localStorage.getItem('user')) || null,
    // Reconnect state management
    backendRetryCount: 0,
    daemonRetryCount: 0,
    backendRetryTimer: null,
    daemonRetryTimer: null,
    backendConnecting: false,
    daemonConnecting: false,
    language: (() => {
      // Verwende die gleiche Logik wie in main.js
      const browserLanguage = navigator.language || navigator.languages[0];
      const germanSpeakingCountries = ['de', 'at', 'ch', 'li'];
      
      if (browserLanguage.startsWith('de')) {
        return 'de';
      }
      
      const allLanguages = navigator.languages || [navigator.language];
      for (const lang of allLanguages) {
        if (lang.startsWith('de-')) {
          const countryCode = lang.split('-')[1]?.toLowerCase();
          if (germanSpeakingCountries.includes(countryCode)) {
            return 'de';
          }
        }
        if (lang.startsWith('de_')) {
          const countryCode = lang.split('_')[1]?.toLowerCase();
          if (germanSpeakingCountries.includes(countryCode)) {
            return 'de';
          }
        }
      }
      
      return 'en';
    })(),
    menu: JSON.parse(localStorage.getItem('menu')) || [],
    socket: null,
    daemonSocket: null,
    menuNeedsUpdate: false,
  },
  mutations: {
    async dologin(state, user) {
      state.isLoggedIn = true;
      state.user = user;
      localStorage.setItem('isLoggedIn', 'true');
      localStorage.setItem('user', JSON.stringify(user));
      state.menuNeedsUpdate = true;
      if (user.param.filter(param => ['birthdate', 'gender'].includes(param.name)).length < 2) {
        router.push({ path: '/settings/personal' });
      }
    },
    async dologout(state) {
      state.isLoggedIn = false;
      state.user = null;
      localStorage.removeItem('isLoggedIn');
      localStorage.removeItem('user');
      localStorage.removeItem('menu');
      state.menuNeedsUpdate = false;
      
      // Setze die Sprache auf die Browser-Sprache zurück
      const browserLanguage = navigator.language || navigator.languages[0];
      const germanSpeakingCountries = ['de', 'at', 'ch', 'li'];
      
      if (browserLanguage.startsWith('de')) {
        state.language = 'de';
      } else {
        const allLanguages = navigator.languages || [navigator.language];
        let isGerman = false;
        for (const lang of allLanguages) {
          if (lang.startsWith('de-')) {
            const countryCode = lang.split('-')[1]?.toLowerCase();
            if (germanSpeakingCountries.includes(countryCode)) {
              isGerman = true;
              break;
            }
          }
          if (lang.startsWith('de_')) {
            const countryCode = lang.split('_')[1]?.toLowerCase();
            if (germanSpeakingCountries.includes(countryCode)) {
              isGerman = true;
              break;
            }
          }
        }
        state.language = isGerman ? 'de' : 'en';
      }
    },
    setLanguage(state, language) {
      state.language = language;
    },
    setMenu(state, menu) {
      state.menu = menu;
      localStorage.setItem('menu', JSON.stringify(menu));
      state.menuNeedsUpdate = false;
    },
    setSocket(state, socket) {
      state.socket = socket;
    },
    setConnectionStatus(state, status) {
      state.connectionStatus = status;
    },
    setDaemonConnectionStatus(state, status) {
      state.daemonConnectionStatus = status;
    },
    clearSocket(state) {
      if (state.socket) {
        state.socket.disconnect();
      }
      state.socket = null;
      // Cleanup retry timer
      if (state.backendRetryTimer) {
        clearTimeout(state.backendRetryTimer);
        state.backendRetryTimer = null;
      }
      state.backendConnecting = false;
    },
    setDaemonSocket(state, daemonSocket) {
      state.daemonSocket = daemonSocket;
    },
    clearDaemonSocket(state) {
      if (state.daemonSocket) {
        state.daemonSocket.close();
      }
      state.daemonSocket = null;
      state.daemonConnectionStatus = 'disconnected';
      // Cleanup retry timer
      if (state.daemonRetryTimer) {
        clearTimeout(state.daemonRetryTimer);
        state.daemonRetryTimer = null;
      }
      state.daemonConnecting = false;
    },
  },
  actions: {
    async login({ commit, dispatch }, user) {
      await commit('dologin', user);
      await dispatch('initializeSocket');
      await dispatch('initializeDaemonSocket');
      const socket = this.getters.socket;
      if (socket) {
        const idForSocket = user?.hashedId || user?.id;
        if (idForSocket) socket.emit('setUserId', idForSocket);
      }
      await dispatch('loadMenu');
    },
    logout({ commit }) {
      commit('clearSocket');
      commit('clearDaemonSocket');
      commit('dologout');
      router.push('/');
    },
    initializeSocket({ commit, state, dispatch }) {
      if (!state.isLoggedIn || !state.user || state.backendConnecting) {
        return;
      }
      
      state.backendConnecting = true;
      
      const connectSocket = () => {
        // Cleanup existing socket and timer
        if (state.socket) {
          state.socket.disconnect();
        }
        if (state.backendRetryTimer) {
          clearTimeout(state.backendRetryTimer);
          state.backendRetryTimer = null;
        }
        
        commit('setConnectionStatus', 'connecting');
        
        // Socket.io URL für lokale Entwicklung und Produktion
        let socketIoUrl = import.meta.env.VITE_SOCKET_IO_URL || import.meta.env.VITE_API_BASE_URL;
        
        // Für lokale Entwicklung: direkte Backend-Verbindung
        if (!socketIoUrl && (import.meta.env.DEV || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1')) {
          socketIoUrl = 'http://localhost:3001';
        }

        // Normalisiere URL (Env-Variablen enthalten teils Pfade wie /api; Port kann absichtlich gesetzt sein, z.B. :4443)
        try {
          if (socketIoUrl) {
            const parsed = new URL(socketIoUrl, window.location.origin);
            // In Produktion: Verwende immer window.location.origin (Port 443), nicht den Port aus der Umgebungsvariable
            // Socket.io wird über Nginx-Proxy auf /socket.io/ weitergeleitet
            if (window.location.hostname === 'www.your-part.de' || window.location.hostname.includes('your-part.de')) {
              socketIoUrl = window.location.origin;
            } else {
              // Lokale Entwicklung: Origin aus parsed verwenden (inkl. Port)
              socketIoUrl = parsed.origin;
            }
          } else {
            // Fallback: aktuelle Origin verwenden
            socketIoUrl = window.location.origin;
          }
        } catch (e) {
          // Wenn Parsing fehlschlägt: letzte Rettung ist der aktuelle Origin
          try {
            socketIoUrl = window.location.origin;
          } catch (_) {}
        }
        
        const socket = io(socketIoUrl, {
          secure: true,
          transports: ['websocket', 'polling']
        });
        
        socket.on('connect', () => {
          state.backendRetryCount = 0; // Reset retry counter on successful connection
          state.backendConnecting = false;
          commit('setConnectionStatus', 'connected');
          const idForSocket = state.user?.hashedId || state.user?.id;
          if (idForSocket) socket.emit('setUserId', idForSocket);
        });

        socket.on('disconnect', (reason) => {
          commit('setConnectionStatus', 'disconnected');
          dispatch('retryBackendConnection');
        });

        socket.on('connect_error', (error) => {
          commit('setConnectionStatus', 'error');
          dispatch('retryBackendConnection');
        });
  
        commit('setSocket', socket);
      };
      
      connectSocket();
    },
    retryBackendConnection({ commit, state }) {
      if (state.backendRetryTimer || state.backendConnecting) {
        return; // Already retrying or connecting
      }
      
      const maxRetries = 10;
      console.log(`Backend-Reconnect-Versuch ${state.backendRetryCount + 1}/${maxRetries}`);
      
      if (state.backendRetryCount >= maxRetries) {
        // Nach maxRetries alle 5 Sekunden weiter versuchen
        console.log('Backend: Max Retries erreicht, versuche weiter alle 5 Sekunden...');
        state.backendRetryTimer = setTimeout(() => {
          state.backendRetryCount = 0; // Reset für nächsten Zyklus
          state.backendRetryTimer = null;
          commit('setConnectionStatus', 'connecting');
          // Recursive call to retry
          setTimeout(() => this.dispatch('retryBackendConnection'), 100);
        }, 5000);
        return;
      }
      
      state.backendRetryCount++;
      const delay = 5000; // Alle 5 Sekunden versuchen
      console.log(`Backend: Warte ${delay}ms bis zum nächsten Reconnect-Versuch...`);
      
      state.backendRetryTimer = setTimeout(() => {
        state.backendRetryTimer = null;
        this.dispatch('initializeSocket');
      }, delay);
    },
    initializeDaemonSocket({ commit, state, dispatch }) {
      if (!state.isLoggedIn || !state.user || state.daemonConnecting) {
        return;
      }

      state.daemonConnecting = true;

      // Daemon URL für lokale Entwicklung und Produktion
      // Vite bindet Umgebungsvariablen zur Build-Zeit ein, daher Fallback-Logik basierend auf Hostname
      const hostname = window.location.hostname;
      const isLocalhost = hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '[::1]';
      const isProduction = hostname === 'www.your-part.de' || hostname.includes('your-part.de');
      
      // Versuche Umgebungsvariable zu lesen (kann undefined sein, wenn nicht zur Build-Zeit gesetzt)
      let daemonUrl = import.meta.env?.VITE_DAEMON_SOCKET;
      
      console.log('[Daemon] Umgebungsvariable VITE_DAEMON_SOCKET:', daemonUrl);
      console.log('[Daemon] DEV-Modus:', import.meta.env?.DEV);
      console.log('[Daemon] Hostname:', hostname);
      console.log('[Daemon] IsLocalhost:', isLocalhost);
      console.log('[Daemon] IsProduction:', isProduction);
      
      // Wenn Umgebungsvariable nicht gesetzt ist oder leer, verwende Fallback-Logik
      if (!daemonUrl || (typeof daemonUrl === 'string' && daemonUrl.trim() === '')) {
        // In Produktion: Verwende /ws/ über Nginx-Proxy (Port 443)
        if (isProduction) {
          const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
          daemonUrl = `${protocol}//${hostname}/ws/`;
          console.log('[Daemon] Verwende Nginx-Proxy /ws/ über Port 443');
        } else {
          // Lokale Entwicklung: direkte Verbindung zum Daemon-Port 4551
          const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
          daemonUrl = `${protocol}//${hostname}:4551/`;
          console.log('[Daemon] Verwende Fallback basierend auf Hostname, Protokoll und Port 4551');
        }
      } else {
        // Wenn Umgebungsvariable gesetzt ist, aber in Produktion: Konvertiere Port 4551 zu /ws/
        if (isProduction && daemonUrl.includes(':4551')) {
          const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
          daemonUrl = `${protocol}//${hostname}/ws/`;
          console.log('[Daemon] Konvertiere Port 4551 zu /ws/ für Nginx-Proxy');
        } else {
          console.log('[Daemon] Verwende Umgebungsvariable');
        }
      }
      
      console.log('[Daemon] Finale Daemon-URL:', daemonUrl);
      
      const connectDaemonSocket = () => {
        // Cleanup existing socket and timer
        if (state.daemonSocket) {
          state.daemonSocket.close();
        }
        if (state.daemonRetryTimer) {
          clearTimeout(state.daemonRetryTimer);
          state.daemonRetryTimer = null;
        }

        // Protokoll-Fallback: zuerst mit Subprotokoll, dann ohne
        const protocols = ['yourpart-protocol', undefined];
        let attemptIndex = 0;

        const tryConnectWithProtocol = () => {
          const currentProtocol = protocols[attemptIndex];
          try {
            commit('setDaemonConnectionStatus', 'connecting');
            const daemonSocket = currentProtocol
              ? new WebSocket(daemonUrl, currentProtocol)
              : new WebSocket(daemonUrl);

            let opened = false;

            daemonSocket.onopen = () => {
              opened = true;
              state.daemonRetryCount = 0;
              state.daemonConnecting = false;
              if (state.daemonRetryTimer) {
                clearTimeout(state.daemonRetryTimer);
                state.daemonRetryTimer = null;
              }
              commit('setDaemonConnectionStatus', 'connected');
              
              // Warte kurz, bevor setUserId gesendet wird, damit der Daemon bereit ist
              // Close-Code 1006 deutet darauf hin, dass der Daemon die Verbindung schließt,
              // möglicherweise weil setUserId zu früh gesendet wird
              setTimeout(() => {
                try {
                  if (daemonSocket.readyState === WebSocket.OPEN && state.isLoggedIn && state.user) {
                    const payload = JSON.stringify({
                      event: 'setUserId',
                      data: { userId: state.user.id }
                    });
                    daemonSocket.send(payload);
                    console.log('[Daemon] setUserId gesendet für User:', state.user.id);
                  } else {
                    console.warn('[Daemon] Socket nicht mehr offen oder Benutzer nicht eingeloggt beim Senden von setUserId');
                  }
                } catch (error) {
                  console.error('[Daemon] Fehler beim Senden von setUserId:', error);
                }
              }, 100); // 100ms Delay
            };

            daemonSocket.onclose = (event) => {
              state.daemonConnecting = false;
              commit('setDaemonConnectionStatus', 'disconnected');
              
              // Detailliertes Logging für Close-Events
              const closeCodeMessages = {
                1000: 'Normal closure',
                1001: 'Going away',
                1002: 'Protocol error',
                1003: 'Unsupported data',
                1006: 'Abnormal closure (no close frame received)',
                1007: 'Invalid data',
                1008: 'Policy violation',
                1009: 'Message too big',
                1010: 'Extension error',
                1011: 'Internal server error'
              };
              const closeMessage = closeCodeMessages[event.code] || `Unknown code: ${event.code}`;
              console.warn(`[Daemon] Verbindung geschlossen - Code: ${event.code} (${closeMessage}), Reason: ${event.reason || 'none'}, WasClean: ${event.wasClean}, Opened: ${opened}`);
              
              // Bereinige Socket-Referenz wenn Verbindung geschlossen wurde
              if (state.daemonSocket === daemonSocket) {
                state.daemonSocket = null;
              }
              
              if (!opened && attemptIndex < protocols.length - 1) {
                attemptIndex += 1;
                tryConnectWithProtocol();
                return;
              }
              
              // Nur reconnen, wenn Benutzer noch eingeloggt ist
              if (state.isLoggedIn && state.user) {
                dispatch('retryDaemonConnection');
              }
            };

            daemonSocket.onerror = (error) => {
              state.daemonConnecting = false;
              commit('setDaemonConnectionStatus', 'error');
              
              console.error('[Daemon] WebSocket-Fehler:', error, 'ReadyState:', daemonSocket.readyState, 'URL:', daemonUrl);
              
              // Detaillierte Fehlermeldung für häufige Probleme
              if (daemonSocket.readyState === WebSocket.CLOSED) {
                const urlObj = new URL(daemonUrl);
                console.error(`[Daemon] Verbindung fehlgeschlagen zu ${urlObj.hostname}:${urlObj.port}`);
                console.error('[Daemon] Mögliche Ursachen:');
                console.error('  - Daemon-Server läuft nicht auf diesem Port');
                console.error('  - Port ist durch Firewall blockiert');
                console.error('  - Falscher Port in VITE_DAEMON_SOCKET');
                console.error(`  - Aktuell konfiguriert: ${daemonUrl}`);
              }
              
              // Bereinige Socket-Referenz bei Fehler
              if (state.daemonSocket === daemonSocket) {
                state.daemonSocket = null;
              }
              
              if (!opened && attemptIndex < protocols.length - 1) {
                attemptIndex += 1;
                tryConnectWithProtocol();
                return;
              }
              
              // Nur reconnen, wenn Benutzer noch eingeloggt ist
              if (state.isLoggedIn && state.user) {
                dispatch('retryDaemonConnection');
              }
            };

            daemonSocket.addEventListener('message', (event) => {
              const message = event.data;
              if (message === "ping") {
                daemonSocket.send("pong");
              } else {
                try {
                  const data = JSON.parse(message);
                  // Handle daemon messages here
                } catch (error) {
                  // Error parsing daemon message
                }
              }
            });

            commit('setDaemonSocket', daemonSocket);
          } catch (error) {
            state.daemonConnecting = false;
            if (attemptIndex < protocols.length - 1) {
              attemptIndex += 1;
              tryConnectWithProtocol();
              return;
            }
            dispatch('retryDaemonConnection');
          }
        };

        tryConnectWithProtocol();
      };

      connectDaemonSocket();
    },
    retryDaemonConnection({ commit, state, dispatch }) {
      // Prüfe ob Benutzer noch eingeloggt ist
      if (!state.isLoggedIn || !state.user) {
        console.log('[Daemon] Benutzer nicht eingeloggt, keine Wiederherstellung der Verbindung');
        return;
      }
      
      // Prüfe ob bereits ein Timer läuft
      if (state.daemonRetryTimer) {
        return;
      }
      
      // Maximale Anzahl von Versuchen: 15
      const maxRetries = 15;
      if (state.daemonRetryCount >= maxRetries) {
        console.warn(`[Daemon] Maximale Anzahl von Reconnect-Versuchen (${maxRetries}) erreicht.`);
        console.warn('[Daemon] Bitte prüfen Sie:');
        console.warn('  1. Läuft der Daemon-Server?');
        console.warn('  2. Ist der Port in VITE_DAEMON_SOCKET korrekt?');
        console.warn('  3. Ist der Port durch Firewall/Netzwerk erreichbar?');
        console.warn(`  4. Aktuell konfiguriert: ${import.meta.env?.VITE_DAEMON_SOCKET || 'nicht gesetzt'}`);
        // Warte länger nach maximalen Versuchen (30 Sekunden)
        state.daemonRetryCount = 0; // Reset für nächsten Zyklus
        const delay = 30000;
        state.daemonRetryTimer = setTimeout(() => {
          state.daemonRetryTimer = null;
          commit('setDaemonConnectionStatus', 'connecting');
          dispatch('initializeDaemonSocket');
        }, delay);
        return;
      }
      
      state.daemonConnecting = false;
      state.daemonRetryCount++;
      const delay = 5000;
      console.log(`[Daemon] Reconnect-Versuch ${state.daemonRetryCount}/${maxRetries}, nächster Versuch in ${delay}ms...`);
      
      state.daemonRetryTimer = setTimeout(() => {
        state.daemonRetryTimer = null;
        // Prüfe noch einmal, ob Benutzer noch eingeloggt ist
        if (state.isLoggedIn && state.user) {
          commit('setDaemonConnectionStatus', 'connecting');
          dispatch('initializeDaemonSocket');
        }
      }, delay);
    },
    setLanguage({ commit }, language) {
      commit('setLanguage', language);
    },
    async loadMenu({ commit }) {
      try {
        const menu = await loadMenu();
        commit('setMenu', menu);
      } catch (err) {
        commit('setMenu', []);
      }
    },
  },
  getters: {
    isLoggedIn: state => state.isLoggedIn,
    user: state => state.user,
    language: state => state.language,
    menu: state => state.menu,
    socket: state => state.socket,
    daemonSocket: state => state.daemonSocket,
    menuNeedsUpdate: state => state.menuNeedsUpdate,
    connectionStatus: state => state.connectionStatus,
    daemonConnectionStatus: state => state.daemonConnectionStatus,
  },
  modules: {
    dialogs,
  },
});

// Initialisierung beim Laden der Anwendung - nur einmal ausführen
if (store.state.isLoggedIn && store.state.user && !store.state.backendConnecting && !store.state.daemonConnecting) {
  store.dispatch('initializeSocket');
  store.dispatch('initializeDaemonSocket');
}

export default store;
