<template>
  <section class="display-page">
    <div class="campo">
      <span v-if="state.order">
        <!-- Ordine visualizzazione: home / guest -->
        <div class="hea home">
          <span :style="{ 'float': 'left' }">
            {{ state.sp.nomi.home }}
            <span class="serv-slot">
              <img v-show="state.sp.servHome" src="/serv.png" width="25" alt="Servizio" />
            </span>
            <span v-if="state.visuForm" class="score-inline">{{ state.sp.punt.home }}</span>
          </span>
          <span class="mr3" :style="{ 'float': 'right' }">set {{ state.sp.set.home }}</span>
        </div>

        <div class="hea guest">
          <span :style="{ 'float': 'right' }">
            <span v-if="state.visuForm" class="score-inline">{{ state.sp.punt.guest }}</span>
            <span class="serv-slot">
              <img v-show="!state.sp.servHome" src="/serv.png" width="25" alt="Servizio" />
            </span>
            {{ state.sp.nomi.guest }}
          </span>
          <span class="ml3" :style="{ 'float': 'left' }">set {{ state.sp.set.guest }}</span>
        </div>

        <span v-if="state.visuForm">
          <div class="col form home">
            <div class="formdiv" v-for="x in [3, 2, 1, 4, 5, 0]" :key="'hf'+x">
              {{ state.sp.form.home[x] }}
            </div>
          </div>
          <div class="col form guest">
            <div class="formdiv" v-for="x in [3, 2, 1, 4, 5, 0]" :key="'gf'+x">
              {{ state.sp.form.guest[x] }}
            </div>
          </div>
        </span>
        <span v-else>
          <div class="punteggio-container">
            <div class="col punt home">{{ state.sp.punt.home }}</div>
            <div class="col punt guest">{{ state.sp.punt.guest }}</div>
          </div>
        </span>
      </span>

      <span v-else>
        <!-- Ordine visualizzazione: guest / home -->
        <div class="hea guest">
          <span :style="{ 'float': 'left' }">
            {{ state.sp.nomi.guest }}
            <span class="serv-slot">
              <img v-show="!state.sp.servHome" src="/serv.png" width="25" alt="Servizio" />
            </span>
            <span v-if="state.visuForm" class="score-inline">{{ state.sp.punt.guest }}</span>
          </span>
          <span class="mr3" :style="{ 'float': 'right' }">set {{ state.sp.set.guest }}</span>
        </div>

        <div class="hea home">
          <span :style="{ 'float': 'right' }">
            <span v-if="state.visuForm" class="score-inline">{{ state.sp.punt.home }}</span>
            <span class="serv-slot">
              <img v-show="state.sp.servHome" src="/serv.png" width="25" alt="Servizio" />
            </span>
            {{ state.sp.nomi.home }}
          </span>
          <span class="ml3" :style="{ 'float': 'left' }">set {{ state.sp.set.home }}</span>
        </div>

        <span v-if="state.visuForm">
          <div class="col form guest">
            <div class="formdiv" v-for="x in [3, 2, 1, 4, 5, 0]" :key="'gf2'+x">
              {{ state.sp.form.guest[x] }}
            </div>
          </div>
          <div class="col form home">
            <div class="formdiv" v-for="x in [3, 2, 1, 4, 5, 0]" :key="'hf2'+x">
              {{ state.sp.form.home[x] }}
            </div>
          </div>
        </span>
        <span v-else>
          <div class="punteggio-container">
            <div class="col punt guest">{{ state.sp.punt.guest }}</div>
            <div class="col punt home">{{ state.sp.punt.home }}</div>
          </div>
        </span>
      </span>

      <div class="striscia" v-if="state.visuStriscia">
        <span class="striscia-nome text-bold">{{ state.sp.nomi.home }}</span>
        <div class="striscia-items" ref="homeItems">
          <div v-for="(h, i) in state.sp.striscia.home" :key="'sh'+i"
               class="item" :class="{ 'item-vuoto': String(h).trim() === '' }">
            {{ String(h) }}
          </div>
        </div>
        <span class="striscia-nome text-bold guest-striscia">{{ state.sp.nomi.guest }}</span>
        <div class="striscia-items guest-striscia" ref="guestItems">
          <div v-for="(h, i) in state.sp.striscia.guest" :key="'sg'+i"
               class="item" :class="{ 'item-vuoto': String(h).trim() === '' }">
            {{ String(h) }}
          </div>
        </div>
      </div>

      <!-- Indicatore stato connessione -->
      <div class="connection-status" :class="{ connected: wsConnected, disconnected: !wsConnected }">
        <span class="dot"></span>
        {{ wsConnected ? '' : 'Disconnesso' }}
      </div>
    </div>
  </section>
</template>

<script>
export default {
  name: "DisplayPage",
  data() {
    return {
      ws: null,
      wsConnected: false,
      isConnecting: false,
      reconnectTimeout: null,
      reconnectAttempts: 0,
      maxReconnectDelay: 30000, // Ritardo massimo di riconnessione: 30 secondi
      state: {
        order: true,
        visuForm: false,
        visuStriscia: true,
        modalitaPartita: "3/5",
        sp: {
          striscia: { home: [0], guest: [0] },
          servHome: true,
          punt: { home: 0, guest: 0 },
          set: { home: 0, guest: 0 },
          nomi: { home: "Antoniana", guest: "Guest" },
          form: {
            home: ["1", "2", "3", "4", "5", "6"],
            guest: ["1", "2", "3", "4", "5", "6"],
          },
          storicoServizio: [],
        },
      },
    }
  },
  mounted() {
    this.connectWebSocket()
    // Attiva la modalita fullscreen su dispositivi mobili.
    if (this.isMobile()) {
      try { document.documentElement.requestFullscreen() } catch (e) {}
    }

    // Gestisce l'HMR di Vite evitando riconnessioni durante la ricarica a caldo.
    if (import.meta.hot) {
      import.meta.hot.on('vite:beforeUpdate', () => {
        // Annulla eventuali tentativi di riconnessione pianificati.
        if (this.reconnectTimeout) {
          clearTimeout(this.reconnectTimeout)
          this.reconnectTimeout = null
        }
      })
    }
  },
  beforeUnmount() {
    // Pulisce il timeout di riconnessione.
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout)
      this.reconnectTimeout = null
    }

    // Chiude il WebSocket con il codice di chiusura appropriato.
    if (this.ws) {
      this.ws.onclose = null // Rimuove il listener per evitare nuove riconnessioni pianificate.
      this.ws.onerror = null
      this.ws.onmessage = null
      this.ws.onopen = null

      // Usa il codice 1000 (chiusura normale) se la connessione e aperta.
      try {
        if (this.ws.readyState === WebSocket.OPEN) {
          this.ws.close(1000, 'Component unmounting')
        } else if (this.ws.readyState === WebSocket.CONNECTING) {
          // Se la connessione e ancora in fase di apertura, chiude direttamente.
          this.ws.close()
        }
      } catch (err) {
        console.error('[Display] Error closing WebSocket:', err)
      }
      this.ws = null
    }
  },
  watch: {
    'state.sp.striscia.home': {
      deep: true,
      handler() {
        this.$nextTick(() => {
          if (this.$refs.homeItems) this.$refs.homeItems.scrollLeft = this.$refs.homeItems.scrollWidth
        })
      }
    },
    'state.sp.striscia.guest': {
      deep: true,
      handler() {
        this.$nextTick(() => {
          if (this.$refs.guestItems) this.$refs.guestItems.scrollLeft = this.$refs.guestItems.scrollWidth
        })
      }
    }
  },
  methods: {
    isMobile() {
      return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
    },
    connectWebSocket() {
      // Evita connessioni simultanee multiple.
      if (this.isConnecting) {
        console.log('[Display] Already connecting, skipping...')
        return
      }

      // Chiude la connessione precedente, se presente.
      if (this.ws) {
        this.ws.onclose = null
        this.ws.onerror = null
        this.ws.onmessage = null
        this.ws.onopen = null
        try {
          if (this.ws.readyState === WebSocket.OPEN) {
            this.ws.close(1000, 'Reconnecting')
          } else if (this.ws.readyState === WebSocket.CONNECTING) {
            this.ws.close()
          }
        } catch (err) {
          console.error('[Display] Error closing previous WebSocket:', err)
        }
        this.ws = null
      }

      this.isConnecting = true
      const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'

      // Permette di specificare un host WebSocket alternativo via query parameter
      // Utile per scenari WSL2 o development remoto: ?wsHost=192.168.1.100:5173
      const params = new URLSearchParams(location.search)
      const defaultHost = (
        location.hostname === 'localhost' || location.hostname === '::1'
      )
        ? `127.0.0.1${location.port ? `:${location.port}` : ''}`
        : location.host
      const wsHost = params.get('wsHost') || defaultHost
      const wsUrl = `${protocol}//${wsHost}/ws`

      console.log('[Display] Connecting to WebSocket:', wsUrl)

      try {
        this.ws = new WebSocket(wsUrl)
      } catch (err) {
        console.error('[Display] Failed to create WebSocket:', err)
        this.isConnecting = false
        this.scheduleReconnect()
        return
      }

      this.ws.onopen = () => {
        this.isConnecting = false
        this.wsConnected = true
        this.reconnectAttempts = 0
        console.log('[Display] Connected to server')

        // Registra il client come display solo con connessione effettivamente aperta.
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
          try {
            this.ws.send(JSON.stringify({ type: 'register', role: 'display' }))
          } catch (err) {
            console.error('[Display] Failed to register:', err)
          }
        }
      }

      this.ws.onmessage = (event) => {
        try {
          const msg = JSON.parse(event.data)

          if (msg.type === 'state') {
            this.state = msg.state
          } else if (msg.type === 'speak') {
            this.speakOnDisplay(msg.text)
          } else if (msg.type === 'error') {
            console.error('[Display] Server error:', msg.message)
          }
        } catch (e) {
          console.error('[Display] Error parsing message:', e)
        }
      }

      this.ws.onclose = (event) => {
        this.isConnecting = false
        this.wsConnected = false
        console.log('[Display] Disconnected from server', event.code, event.reason)

        // Non riconnette durante HMR (codice 1001, "going away")
        // ne in caso di chiusura pulita (codice 1000).
        if (event.code === 1000 || event.code === 1001) {
          console.log('[Display] Clean close, not reconnecting')
          return
        }

        this.scheduleReconnect()
      }

      this.ws.onerror = (err) => {
        console.error('[Display] WebSocket error:', err)
        this.isConnecting = false
        this.wsConnected = false
      }
    },
    scheduleReconnect() {
      // Evita pianificazioni multiple della riconnessione.
      if (this.reconnectTimeout) {
        return
      }

      // Applica backoff esponenziale: 1s, 2s, 4s, 8s, 16s, fino a 30s.
      const delay = Math.min(
        1000 * Math.pow(2, this.reconnectAttempts),
        this.maxReconnectDelay
      )
      this.reconnectAttempts++

      console.log(`[Display] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`)

      this.reconnectTimeout = setTimeout(() => {
        this.reconnectTimeout = null
        this.connectWebSocket()
      }, delay)
    },
    speakOnDisplay(text) {
      if (typeof text !== 'string' || !text.trim()) {
        return
      }
      if (!('speechSynthesis' in window)) {
        console.warn('[Display] speechSynthesis not supported')
        return
      }

      const utterance = new SpeechSynthesisUtterance(text.trim())
      const voices = window.speechSynthesis.getVoices()
      const preferredVoice = voices.find((v) => v.name === 'Google italiano')
        || voices.find((v) => v.lang && v.lang.toLowerCase().startsWith('it'))
      if (preferredVoice) {
        utterance.voice = preferredVoice
      }
      utterance.lang = 'it-IT'

      window.speechSynthesis.cancel()
      window.speechSynthesis.speak(utterance)
    }
  }
}
</script>

<style scoped>
.display-page {
  width: 100%;
  height: 100vh;
  background: #000;
  overflow: hidden;
}

.connection-status {
  position: fixed;
  top: 8px;
  right: 8px;
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  gap: 5px;
  z-index: 100;
  transition: opacity 0.5s;
}

.connection-status.connected {
  opacity: 0;
}

.connection-status.disconnected {
  background: rgba(255, 50, 50, 0.8);
  color: white;
  opacity: 1;
}

.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
}

.connected .dot {
  background: #4caf50;
}

.disconnected .dot {
  background: #f44336;
  animation: blink 1s infinite;
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

.guest-striscia {
  color: white;
}

.punteggio-container {
  width: 100%;
  display: flex;
}

.punt {
  font-size: 60vh;
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 50vh;
  min-width: 50vw;
  max-width: 50vw;
  overflow: hidden;
  box-sizing: border-box;
}
</style>
