package udp

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"strings"

	"hamlog/internal/applog"
)

// WSJT-X Halt Tx (message type 8) — "stop transmitting".
//
// The same two things the Halt Tx button and the Enable Tx toggle do in the
// application's own window:
//
//	Halt Tx  type 8
//	  id            utf8  the target application's own id
//	  auto_tx_only  bool  false = stop the transmission NOW
//	                      true  = let this over finish, then stop auto-Tx
//
// Both are useful and they are not the same operation. Stopping mid-over is what
// you want when you have called the wrong station or realised the frequency is
// occupied; finishing the over first is what you want when the QSO is complete
// and cutting the transmission would leave the other end waiting for a report
// that never lands.
const wsjtMsgHaltTx = 8

// EncodeHaltTx builds the datagram. autoTxOnly false halts immediately.
func EncodeHaltTx(programID string, autoTxOnly bool) []byte {
	var b bytes.Buffer
	_ = binary.Write(&b, binary.BigEndian, uint32(wsjtMagic))
	_ = binary.Write(&b, binary.BigEndian, uint32(2)) // schema 2 — what every current sender speaks
	_ = binary.Write(&b, binary.BigEndian, uint32(wsjtMsgHaltTx))
	writeQString(&b, programID)
	var auto uint8
	if autoTxOnly {
		auto = 1
	}
	_ = binary.Write(&b, binary.BigEndian, auto)
	return b.Bytes()
}

// SendHaltTx tells one decoding application to stop transmitting.
//
// Routed by PROGRAM ID and answered back to the address that instance's packets
// arrive from, exactly like SendReply: two receivers can share one multicast
// group, and halting the 20 m instance because the 6 m one is transmitting would
// be worse than doing nothing.
func (m *Manager) SendHaltTx(programID string, autoTxOnly bool) error {
	if strings.TrimSpace(programID) == "" {
		return fmt.Errorf("no application id — cannot tell which receiver to halt")
	}
	m.mu.Lock()
	servers := make([]*Server, 0, len(m.inbound))
	for _, s := range m.inbound {
		servers = append(servers, s)
	}
	m.mu.Unlock()

	for _, s := range servers {
		conn, addr := s.replyTarget(programID)
		if conn == nil || addr == nil {
			continue
		}
		if _, err := conn.WriteToUDP(EncodeHaltTx(programID, autoTxOnly), addr); err != nil {
			return fmt.Errorf("send halt to %s at %s: %w", programID, addr, err)
		}
		applog.Printf("udp: halt tx sent to %s at %s (auto_tx_only=%v)", programID, addr, autoTxOnly)
		return nil
	}
	return fmt.Errorf("no packet has arrived from %q yet — nothing to halt", programID)
}
