/**
 * Store Pinia pour la gestion des IPs
 */
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import axios from 'axios'

export const useIPStore = defineStore('ip', () => {
  // État
  const ips = ref([])
  const selectedIP = ref(null)
  const loading = ref(false)
  const error = ref(null)
  const stats = ref({
    total: 0,
    online: 0,
    offline: 0,
    known: 0,
    unknown: 0
  })
  const searchQuery = ref('')
  const invertSearch = ref(false)
  const lastScanDate = ref(null)
  const scanProgress = ref({
    current: 0,
    total: 0,
    currentIP: null
  })
  const scanLogs = ref([])
  const isScanning = ref(false)
  const uiConfig = ref({
    cell_size: 30,
    architecture_title_font_size: 18
  })
  const configReloadTick = ref(0)

  // WebSocket
  const ws = ref(null)
  const wsConnected = ref(false)

  // Computed
  const filteredIPs = computed(() => {
    const { tokens, flags } = parseSearchQuery(searchQuery.value)

    return ips.value.filter(ip => {
      if (flags.requireOnline && ip.last_status !== 'online') return false
      if (flags.requireOffline && ip.last_status !== 'offline') return false
      if (flags.requireFree && ip.last_status) return false
      if (flags.requireKnown && !ip.known) return false
      if (flags.requireUnknown && ip.known) return false
      if (flags.requireTracked && !ip.tracked) return false
      if (flags.requireVm && !ip.vm) return false
      if (flags.requireHardwareBench && !ip.hardware_bench) return false

      let matches = true

      if (tokens.length === 0) {
        matches = true
      } else {
        const haystack = normalizeText([
          ip.ip,
          ip.name,
          ip.hostname,
          ip.host,
          ip.location,
          ip.mac,
          ip.vendor,
          ip.link,
        ip.last_status,
        ip.tracked ? 'suivie' : '',
        ip.vm ? 'vm' : '',
        ip.hardware_bench ? 'hardware' : '',
          (ip.open_ports || []).join(' ')
        ].filter(Boolean).join(' '))

        // Match si au moins un mot est présent
        matches = tokens.some(token => haystack.includes(token))
      }

      return invertSearch.value ? !matches : matches
    })
  })

  // Actions
  async function fetchUIConfig() {
    try {
      const response = await axios.get('/api/config/ui')
      uiConfig.value = response.data
      // Appliquer la taille des cellules, de la police et de l'espacement via variables CSS
      document.documentElement.style.setProperty('--cell-size', `${response.data.cell_size}px`)
      document.documentElement.style.setProperty('--font-size', `${response.data.font_size}px`)
      document.documentElement.style.setProperty('--cell-gap', `${response.data.cell_gap}px`)
      document.documentElement.style.setProperty(
        '--arch-title-size',
        `${response.data.architecture_title_font_size}px`
      )
    } catch (err) {
      console.error('Erreur chargement config UI:', err)
    }
  }

  async function reloadConfig() {
    try {
      const response = await axios.post('/api/config/reload')
      if (response.data.success) {
        // Appliquer la nouvelle config UI
        uiConfig.value = response.data.ui
        document.documentElement.style.setProperty('--cell-size', `${response.data.ui.cell_size}px`)
        document.documentElement.style.setProperty('--font-size', `${response.data.ui.font_size}px`)
        document.documentElement.style.setProperty('--cell-gap', `${response.data.ui.cell_gap}px`)
        document.documentElement.style.setProperty(
          '--arch-title-size',
          `${response.data.ui.architecture_title_font_size}px`
        )
        return response.data.message
      }
    } catch (err) {
      console.error('Erreur rechargement config:', err)
      throw err
    }
  }

  function bumpConfigReload() {
    configReloadTick.value += 1
  }

  async function fetchIPs() {
    loading.value = true
    error.value = null

    try {
      const response = await axios.get('/api/ips/')
      ips.value = response.data
      await fetchStats()
    } catch (err) {
      error.value = err.message
      console.error('Erreur chargement IPs:', err)
    } finally {
      loading.value = false
    }
  }

  async function fetchStats() {
    try {
      const response = await axios.get('/api/ips/stats/summary')
      stats.value = response.data
    } catch (err) {
      console.error('Erreur chargement stats:', err)
    }
  }

  async function updateIP(ipAddress, data) {
    try {
      const response = await axios.put(`/api/ips/${ipAddress}`, data)

      // Mettre à jour dans le store
      const index = ips.value.findIndex(ip => ip.ip === ipAddress)
      if (index !== -1) {
        ips.value[index] = response.data
      }

      if (selectedIP.value?.ip === ipAddress) {
        selectedIP.value = response.data
      }

      return response.data
    } catch (err) {
      error.value = err.message
      throw err
    }
  }

  async function deleteIP(ipAddress) {
    try {
      await axios.delete(`/api/ips/${ipAddress}`)

      // Retirer du store
      const index = ips.value.findIndex(ip => ip.ip === ipAddress)
      if (index !== -1) {
        ips.value.splice(index, 1)
      }

      if (selectedIP.value?.ip === ipAddress) {
        selectedIP.value = null
      }

      await fetchStats()
    } catch (err) {
      error.value = err.message
      throw err
    }
  }

  async function getIPHistory(ipAddress, hours = 24) {
    try {
      const response = await axios.get(`/api/ips/${ipAddress}/history?hours=${hours}`)
      return response.data
    } catch (err) {
      console.error('Erreur chargement historique:', err)
      throw err
    }
  }

  async function startScan() {
    try {
      await axios.post('/api/scan/start')
    } catch (err) {
      error.value = err.message
      throw err
    }
  }

  function selectIP(ip) {
    selectedIP.value = ip
  }

  function clearSelection() {
    selectedIP.value = null
  }

  // WebSocket
  function connectWebSocket() {
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const wsUrl = `${protocol}//${window.location.host}/ws`

    ws.value = new WebSocket(wsUrl)

    ws.value.onopen = () => {
      console.log('WebSocket connecté')
      wsConnected.value = true

      // Heartbeat toutes les 30s
      setInterval(() => {
        if (ws.value?.readyState === WebSocket.OPEN) {
          ws.value.send('ping')
        }
      }, 30000)
    }

    ws.value.onmessage = (event) => {
      // Ignorer les messages ping/pong (texte brut)
      if (typeof event.data === 'string' && (event.data === 'ping' || event.data === 'pong')) {
        return
      }

      try {
        const message = JSON.parse(event.data)
        handleWebSocketMessage(message)
      } catch (err) {
        // Ignorer silencieusement les erreurs de parsing pour les messages non-JSON
      }
    }

    ws.value.onerror = (error) => {
      // Erreur WebSocket - ne pas logger si c'est juste une déconnexion normale
      wsConnected.value = false
    }

    ws.value.onclose = (event) => {
      wsConnected.value = false

      // Ne logger que si c'est une fermeture anormale
      if (!event.wasClean) {
        console.log('WebSocket déconnecté - reconnexion dans 5s...')
      }

      // Reconnexion après 5s
      setTimeout(() => {
        // Ne reconnecter que si on n'est pas déjà connecté
        if (!ws.value || ws.value.readyState === WebSocket.CLOSED) {
          connectWebSocket()
        }
      }, 5000)
    }
  }

  function handleWebSocketMessage(message) {
    // Logger uniquement les messages importants (pas scan_progress pour éviter le spam)
    if (message.type !== 'scan_progress') {
      console.log('WebSocket:', message.type)
    }

    switch (message.type) {
      case 'scan_start':
        // Notification début de scan
        isScanning.value = true
        scanLogs.value = []
        scanProgress.value = {
          current: 0,
          total: message.total || 0,
          currentIP: null
        }
        break

      case 'scan_progress':
        // Progression du scan
        if (message.current) scanProgress.value.current = message.current
        if (message.total) scanProgress.value.total = message.total
        if (message.ip) scanProgress.value.currentIP = message.ip
        break

      case 'scan_complete':
        // Rafraîchir les données après scan
        isScanning.value = false
        lastScanDate.value = new Date()
        scanProgress.value = { current: 0, total: 0, currentIP: null }
        fetchIPs()
        if (message.stats) stats.value = message.stats
        break

      case 'ip_update':
        // Mise à jour d'une IP
        const updatedIP = ips.value.find(ip => ip.ip === message.data.ip)
        if (updatedIP) {
          Object.assign(updatedIP, message.data)
        }
        break

      case 'new_ip':
        // Nouvelle IP détectée
        fetchIPs() // Recharger pour être sûr
        break
      case 'scan_log':
        if (message.message) {
          scanLogs.value.push(message.message)
          if (scanLogs.value.length > 200) {
            scanLogs.value.splice(0, scanLogs.value.length - 200)
          }
        }
        break
    }
  }

  function disconnectWebSocket() {
    if (ws.value) {
      ws.value.close()
      ws.value = null
      wsConnected.value = false
    }
  }

  return {
    // État
    ips,
    selectedIP,
    loading,
    error,
    stats,
    searchQuery,
    invertSearch,
    ws,
    wsConnected,
    lastScanDate,
    scanProgress,
    scanLogs,
    isScanning,
    uiConfig,
    configReloadTick,

    // Computed
    filteredIPs,

    // Actions
    fetchUIConfig,
    reloadConfig,
    bumpConfigReload,
    fetchIPs,
    fetchStats,
    updateIP,
    deleteIP,
    getIPHistory,
    startScan,
    selectIP,
    clearSelection,
    connectWebSocket,
    disconnectWebSocket
  }
})

function normalizeText(value) {
  return String(value ?? '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLowerCase()
    .trim()
}

function parseSearchQuery(query) {
  let normalized = normalizeText(query)

  const flags = {
    requireOnline: false,
    requireOffline: false,
    requireKnown: false,
    requireUnknown: false,
    requireFree: false,
    requireTracked: false,
    requireVm: false,
    requireHardwareBench: false
  }

  const onlinePattern = /\ben\s+ligne\b/g
  const offlinePattern = /\bhors\s+ligne\b/g

  if (onlinePattern.test(normalized)) flags.requireOnline = true
  if (offlinePattern.test(normalized)) flags.requireOffline = true

  normalized = normalized
    .replace(onlinePattern, ' ')
    .replace(offlinePattern, ' ')

  let tokens = normalized.split(/\s+/).filter(Boolean)

  tokens = tokens.filter(token => {
    if (token === 'connue') {
      flags.requireKnown = true
      return false
    }
    if (token === 'inconnue') {
      flags.requireUnknown = true
      return false
    }
    if (token === 'libre') {
      flags.requireFree = true
      return false
    }
    if (token === 'suivie' || token === 'suivi') {
      flags.requireTracked = true
      return false
    }
    if (token === 'vm') {
      flags.requireVm = true
      return false
    }
    if (token === 'hardware' || token === 'bench' || token === 'hardware_bench') {
      flags.requireHardwareBench = true
      return false
    }
    if (token === 'enligne' || token === 'en-ligne') {
      flags.requireOnline = true
      return false
    }
    if (token === 'horsligne' || token === 'hors-ligne') {
      flags.requireOffline = true
      return false
    }
    return true
  })

  return { tokens, flags }
}
