<template>
  <section class="controller-page">
    <!-- Barra di stato connessione -->
    <div class="conn-bar" :class="{ connected: wsConnected }">
      <span class="dot"></span>
      {{ wsConnected ? 'Connesso' : 'Connessione...' }}
    </div>

    <!-- Anteprima punteggio -->
    <div class="score-preview">
      <div class="team-score home-bg" @click="sendAction({ type: 'incPunt', team: 'home' })">
        <div class="team-name">{{ state.sp.nomi.home }}</div>
        <div class="team-pts">{{ state.sp.punt.home }}</div>
        <div class="team-set">SET {{ state.sp.set.home }}</div>
        <img v-show="state.sp.servHome" src="/serv.png" class="serv-icon" />
      </div>
      <div class="team-score guest-bg" @click="sendAction({ type: 'incPunt', team: 'guest' })">
        <div class="team-name">{{ state.sp.nomi.guest }}</div>
        <div class="team-pts">{{ state.sp.punt.guest }}</div>
        <div class="team-set">SET {{ state.sp.set.guest }}</div>
        <img v-show="!state.sp.servHome" src="/serv.png" class="serv-icon" />
      </div>
    </div>

    <!-- Riga annulla punto -->
    <div class="undo-row">
      <button class="btn btn-undo" @click="sendAction({ type: 'decPunt' })">
        ANNULLA PUNTO
      </button>
    </div>

    <!-- Pulsanti set -->
    <div class="action-row">
      <button class="btn btn-set home-bg" @click="sendAction({ type: 'incSet', team: 'home' })">
        SET {{ state.sp.nomi.home }}
      </button>
      <button class="btn btn-set guest-bg" @click="sendAction({ type: 'incSet', team: 'guest' })">
        SET {{ state.sp.nomi.guest }}
      </button>
    </div>

    <!-- Controlli principali -->
    <div class="controls">
      <button class="btn btn-ctrl" @click="sendAction({ type: 'cambiaPalla' })" :disabled="!isPunteggioZeroZero">
        Cambio Palla
      </button>
      <button class="btn btn-ctrl" @click="sendAction({ type: 'toggleFormazione' })">
        {{ state.visuForm ? 'Punteggio' : 'Formazioni' }}
      </button>
      <button class="btn btn-ctrl" @click="sendAction({ type: 'toggleStriscia' })">
        Striscia
      </button>
      <button class="btn btn-ctrl" @click="sendAction({ type: 'toggleOrder' })">
        Inverti
      </button>
      <button class="btn btn-ctrl" @click="speak()">
        Voce
      </button>
      <button class="btn btn-ctrl" @click="openConfig()">
        Config
      </button>
      <button class="btn btn-ctrl" @click="openCambiTeam()">
        Cambi
      </button>
      <button class="btn btn-danger" @click="confirmReset = true">
        Reset
      </button>
    </div>

    <!-- Finestra conferma reset -->
    <div class="overlay" v-if="confirmReset" @click.self="confirmReset = false">
      <div class="dialog">
        <div class="dialog-title">Azzero punteggio?</div>
        <div class="dialog-buttons">
          <button class="btn btn-cancel" @click="confirmReset = false">NO</button>
          <button class="btn btn-confirm" @click="doReset()">SI</button>
        </div>
      </div>
    </div>

    <!-- Finestra configurazione -->
    <div class="overlay" v-if="showConfig" @click.self="showConfig = false">
      <div class="dialog dialog-config">
        <div class="dialog-title">Configurazione</div>

        <div class="form-group">
          <label>Nome Home</label>
          <input type="text" v-model="configData.nomeHome" class="input-field" />
        </div>
        <div class="form-group">
          <label>Nome Guest</label>
          <input type="text" v-model="configData.nomeGuest" class="input-field" />
        </div>

        <div class="form-group">
          <label>Modalità partita</label>
          <div class="mode-buttons">
            <button :class="['btn', 'btn-mode', configData.modalita === '2/3' ? 'active' : '']"
              @click="configData.modalita = '2/3'">2/3</button>
            <button :class="['btn', 'btn-mode', configData.modalita === '3/5' ? 'active' : '']"
              @click="configData.modalita = '3/5'">3/5</button>
          </div>
        </div>

        <div class="form-group">
          <label>Formazione Home</label>
          <div class="form-grid">
            <div class="form-row">
              <input type="text" v-model="configData.formHome[3]" class="input-num" />
              <input type="text" v-model="configData.formHome[2]" class="input-num" />
              <input type="text" v-model="configData.formHome[1]" class="input-num" />
            </div>
            <div class="form-line"></div>
            <div class="form-row">
              <input type="text" v-model="configData.formHome[4]" class="input-num" />
              <input type="text" v-model="configData.formHome[5]" class="input-num" />
              <input type="text" v-model="configData.formHome[0]" class="input-num" />
            </div>
          </div>
        </div>

        <div class="form-group">
          <label>Formazione Guest</label>
          <div class="form-grid">
            <div class="form-row">
              <input type="text" v-model="configData.formGuest[3]" class="input-num" />
              <input type="text" v-model="configData.formGuest[2]" class="input-num" />
              <input type="text" v-model="configData.formGuest[1]" class="input-num" />
            </div>
            <div class="form-line"></div>
            <div class="form-row">
              <input type="text" v-model="configData.formGuest[4]" class="input-num" />
              <input type="text" v-model="configData.formGuest[5]" class="input-num" />
              <input type="text" v-model="configData.formGuest[0]" class="input-num" />
            </div>
          </div>
        </div>

        <div class="dialog-buttons">
          <button class="btn btn-cancel" @click="showConfig = false">Annulla</button>
          <button class="btn btn-confirm" @click="saveConfig()">OK</button>
        </div>
      </div>
    </div>

    <!-- Selezione squadra per cambi -->
    <div class="overlay" v-if="showCambiTeam" @click.self="showCambiTeam = false">
      <div class="dialog">
        <div class="dialog-title">Scegli squadra</div>
        <div class="dialog-buttons">
          <button class="btn btn-set home-bg" @click="openCambi('home')">{{ state.sp.nomi.home }}</button>
          <button class="btn btn-set guest-bg" @click="openCambi('guest')">{{ state.sp.nomi.guest }}</button>
        </div>
      </div>
    </div>

    <!-- Finestra gestione cambi -->
    <div class="overlay" v-if="showCambi" @click.self="closeCambi()">
      <div class="dialog">
        <div class="dialog-title">{{ state.sp.nomi[cambiTeam] }}: CAMBIO</div>
        <div class="cambi-container">
          <div class="cambio-row" v-for="(c, i) in cambiData" :key="i">
            <input type="text" v-model="c.in" placeholder="IN" class="input-num cambi-in-field" />
            <span class="cambio-arrow">→</span>
            <input type="text" v-model="c.out" placeholder="OUT" class="input-num cambi-out-field" />
          </div>
        </div>
        <div class="dialog-buttons">
          <button class="btn btn-cancel" @click="closeCambi()">Annulla</button>
          <button class="btn btn-confirm" :disabled="!cambiValid" @click="confermaCambi()">CONFERMA</button>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
export default {
  name: "ControllerPage",
  data() {
    return {
      ws: null,
      wsConnected: false,
      isConnecting: false,
      reconnectTimeout: null,
      reconnectAttempts: 0,
      maxReconnectDelay: 30000,
      confirmReset: false,
      showConfig: false,
      showCambiTeam: false,
      showCambi: false,
      cambiTeam: "home",
      cambiData: [
        { in: "", out: "" },
        { in: "", out: "" },
      ],
      configData: {
        nomeHome: "",
        nomeGuest: "",
        modalita: "3/5",
        formHome: ["1", "2", "3", "4", "5", "6"],
        formGuest: ["1", "2", "3", "4", "5", "6"],
      },
      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: [],
        },
      },
    }
  },
  computed: {
    isPunteggioZeroZero() {
      return this.state.sp.punt.home === 0 && this.state.sp.punt.guest === 0
    },
    cambiValid() {
      let hasComplete = false
      let allValid = true
      this.cambiData.forEach((c) => {
        const cin = (c.in || "").trim()
        const cout = (c.out || "").trim()
        if (!cin && !cout) return
        if (!cin || !cout) { allValid = false; return }
        hasComplete = true
      })
      return allValid && hasComplete
    }
  },
  mounted() {
    this.connectWebSocket()

    // 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('[Controller] Error closing WebSocket:', err)
      }
      this.ws = null
    }
  },
  methods: {
    connectWebSocket() {
      // Evita connessioni simultanee multiple.
      if (this.isConnecting) {
        console.log('[Controller] 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('[Controller] 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:3001
      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('[Controller] Connecting to WebSocket:', wsUrl)

      try {
        this.ws = new WebSocket(wsUrl)
      } catch (err) {
        console.error('[Controller] 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('[Controller] Connected to server')

        // Invia la registrazione solo se la connessione e realmente aperta.
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
          try {
            this.ws.send(JSON.stringify({ type: 'register', role: 'controller' }))
          } catch (err) {
            console.error('[Controller] 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 === 'error') {
            console.error('[Controller] Server error:', msg.message)
            // Fornisce feedback di errore all'utente.
            this.showErrorFeedback(msg.message)
          }
        } catch (e) {
          console.error('[Controller] Parse error:', e)
        }
      }

      this.ws.onclose = (event) => {
        this.isConnecting = false
        this.wsConnected = false
        console.log('[Controller] 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('[Controller] Clean close, not reconnecting')
          return
        }

        this.scheduleReconnect()
      }

      this.ws.onerror = (err) => {
        console.error('[Controller] 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(`[Controller] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`)

      this.reconnectTimeout = setTimeout(() => {
        this.reconnectTimeout = null
        this.connectWebSocket()
      }, delay)
    },

    sendAction(action) {
      if (!this.wsConnected || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
        console.warn('[Controller] Cannot send action: not connected')
        this.showErrorFeedback('Non connesso al server')
        return
      }

      // Valida l'azione prima dell'invio.
      if (!action || !action.type) {
        console.error('[Controller] Invalid action format:', action)
        return
      }

      try {
        this.ws.send(JSON.stringify({ type: 'action', action }))
      } catch (err) {
        console.error('[Controller] Failed to send action:', err)
        this.showErrorFeedback('Errore invio comando')
      }
    },

    showErrorFeedback(message) {
      // Feedback visivo degli errori: attualmente solo log su console.
      // In futuro puo essere esteso con notifiche a comparsa (toast).
      console.error('[Controller] Error:', message)
    },

    doReset() {
      this.sendAction({ type: 'resetta' })
      this.confirmReset = false
    },

    openConfig() {
      this.configData.nomeHome = this.state.sp.nomi.home
      this.configData.nomeGuest = this.state.sp.nomi.guest
      this.configData.modalita = this.state.modalitaPartita
      this.configData.formHome = [...this.state.sp.form.home]
      this.configData.formGuest = [...this.state.sp.form.guest]
      this.showConfig = true
    },

    saveConfig() {
      this.sendAction({ type: 'setNomi', home: this.configData.nomeHome, guest: this.configData.nomeGuest })
      this.sendAction({ type: 'setModalita', modalita: this.configData.modalita })
      this.sendAction({ type: 'setFormazione', team: 'home', form: this.configData.formHome })
      this.sendAction({ type: 'setFormazione', team: 'guest', form: this.configData.formGuest })
      this.showConfig = false
    },

    openCambiTeam() {
      this.showCambiTeam = true
    },

    openCambi(team) {
      this.showCambiTeam = false
      this.cambiTeam = team
      this.cambiData = [{ in: "", out: "" }, { in: "", out: "" }]
      this.showCambi = true
    },

    closeCambi() {
      this.showCambi = false
      this.cambiData = [{ in: "", out: "" }, { in: "", out: "" }]
    },

    confermaCambi() {
      if (!this.cambiValid) return
      const cambi = this.cambiData
        .filter(c => (c.in || "").trim() && (c.out || "").trim())
        .map(c => ({ in: c.in.trim(), out: c.out.trim() }))
      this.sendAction({ type: 'confermaCambi', team: this.cambiTeam, cambi })
      this.closeCambi()
    },

    speak() {
      const msg = new SpeechSynthesisUtterance()
      if (this.state.sp.punt.home + this.state.sp.punt.guest === 0) {
        msg.text = "zero a zero"
      } else if (this.state.sp.punt.home === this.state.sp.punt.guest) {
        msg.text = this.state.sp.punt.home + " pari"
      } else {
        if (this.state.sp.servHome) {
          msg.text = this.state.sp.punt.home + " a " + this.state.sp.punt.guest
        } else {
          msg.text = this.state.sp.punt.guest + " a " + this.state.sp.punt.home
        }
      }
      const voices = window.speechSynthesis.getVoices()
      msg.voice = voices.find(v => v.name === 'Google italiano')
      window.speechSynthesis.speak(msg)
    }
  }
}
</script>

<style scoped>
.controller-page {
  min-height: 100vh;
  background: #111;
  color: #fff;
  padding: 8px;
  padding-top: 36px;
  font-family: 'Inter', system-ui, sans-serif;
  -webkit-user-select: none;
  user-select: none;
}

/* Barra stato connessione */
.conn-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  background: #c62828;
  color: white;
  z-index: 200;
  transition: background 0.3s;
}
.conn-bar.connected {
  background: #2e7d32;
}
.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: white;
}

/* Anteprima punteggio */
.score-preview {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
}
.team-score {
  flex: 1;
  border-radius: 16px;
  padding: 16px 12px;
  text-align: center;
  cursor: pointer;
  position: relative;
  transition: transform 0.1s;
  min-height: 120px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.team-score:active {
  transform: scale(0.97);
}
.home-bg {
  background: linear-gradient(145deg, #1a1a1a, #333);
  border: 2px solid #fdd835;
  color: #fdd835;
}
.guest-bg {
  background: linear-gradient(145deg, #0d47a1, #1565c0);
  border: 2px solid #64b5f6;
  color: #fff;
}
.team-name {
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 4px;
}
.team-pts {
  font-size: 56px;
  font-weight: 900;
  line-height: 1;
}
.team-set {
  font-size: 13px;
  font-weight: 600;
  opacity: 0.75;
  margin-top: 4px;
}
.serv-icon {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 20px;
  height: 20px;
}

/* Riga annulla punto */
.undo-row {
  margin-bottom: 8px;
}
.btn-undo {
  width: 100%;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.2);
  color: #ffab91;
  padding: 10px;
  font-size: 14px;
  font-weight: 700;
  border-radius: 12px;
  cursor: pointer;
}
.btn-undo:active {
  background: rgba(255,100,50,0.2);
}

/* Pulsanti set */
.action-row {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
}
.btn-set {
  flex: 1;
  padding: 12px;
  font-size: 13px;
  font-weight: 700;
  border-radius: 12px;
  cursor: pointer;
  border: none;
  text-transform: uppercase;
}
.btn-set:active {
  transform: scale(0.97);
}

/* Griglia controlli */
.controls {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}

.btn {
  border: none;
  font-family: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.btn-ctrl {
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.15);
  color: #e0e0e0;
  padding: 14px 8px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 12px;
  transition: background 0.15s;
}
.btn-ctrl:active {
  background: rgba(255,255,255,0.18);
}
.btn-ctrl:disabled {
  opacity: 0.35;
}

.btn-danger {
  background: rgba(198, 40, 40, 0.25);
  border: 1px solid rgba(239, 83, 80, 0.4);
  color: #ef5350;
  padding: 14px 8px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 12px;
}
.btn-danger:active {
  background: rgba(198, 40, 40, 0.45);
}

/* Overlay e finestre modali */
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0,0,0,0.75);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 300;
  padding: 16px;
}

.dialog {
  background: #1e1e1e;
  border-radius: 20px;
  padding: 24px;
  width: 100%;
  max-width: 400px;
  border: 1px solid rgba(255,255,255,0.12);
}

.dialog-config {
  max-height: 85vh;
  overflow-y: auto;
}

.dialog-title {
  font-size: 18px;
  font-weight: 800;
  text-align: center;
  margin-bottom: 20px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(255,255,255,0.12);
}

.dialog-buttons {
  display: flex;
  gap: 12px;
  margin-top: 20px;
}

.btn-cancel {
  flex: 1;
  background: rgba(255,255,255,0.08);
  color: #aaa;
  padding: 12px;
  border-radius: 12px;
  font-size: 15px;
  font-weight: 600;
}

.btn-confirm {
  flex: 1;
  background: #2e7d32;
  color: white;
  padding: 12px;
  border-radius: 12px;
  font-size: 15px;
  font-weight: 700;
}
.btn-confirm:disabled {
  opacity: 0.4;
}

/* Gruppi form */
.form-group {
  margin-bottom: 16px;
}
.form-group label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: #aaa;
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.input-field {
  width: 100%;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.2);
  color: white;
  padding: 10px 14px;
  border-radius: 10px;
  font-size: 16px;
  box-sizing: border-box;
}
.input-field:focus {
  outline: none;
  border-color: #64b5f6;
}

.input-num {
  width: 52px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.2);
  color: white;
  padding: 8px;
  border-radius: 8px;
  font-size: 18px;
  text-align: center;
  box-sizing: border-box;
}
.input-num:focus {
  outline: none;
  border-color: #64b5f6;
}

/* Griglia formazione */
.form-grid {
  background: rgba(205, 133, 63, 0.15);
  border: 2px solid rgba(255,255,255,0.15);
  border-radius: 12px;
  padding: 12px;
}
.form-row {
  display: flex;
  justify-content: center;
  gap: 10px;
  padding: 8px 0;
}
.form-line {
  border-top: 1px dashed rgba(255,255,255,0.3);
  margin: 4px 0;
}

/* Pulsanti modalita */
.mode-buttons {
  display: flex;
  gap: 8px;
}
.btn-mode {
  flex: 1;
  padding: 10px;
  background: rgba(255,255,255,0.08);
  color: #aaa;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 700;
  transition: all 0.15s;
}
.btn-mode.active {
  background: #2e7d32;
  color: white;
}

/* Sezione cambi */
.cambi-container {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 8px 0;
}
.cambio-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}
.cambio-arrow {
  font-size: 20px;
  font-weight: 700;
  color: #aaa;
}
.cambi-in-field {
  background: rgba(120, 200, 120, 0.2) !important;
  border-color: rgba(120, 200, 120, 0.4) !important;
}
.cambi-out-field {
  background: rgba(200, 120, 120, 0.2) !important;
  border-color: rgba(200, 120, 120, 0.4) !important;
}
</style>
