package decnetfp

import (
	"time"
)

// tryParseH3ControlStream examines raw bytes from the beginning of an h3
// unidirectional stream.  If the stream opens with stream-type 0x00 (h3
// control stream, RFC 9114 §6.2.1) and the first frame is SETTINGS
// (type 0x04), it emits an h3_settings fp record.  All errors are silent.
func tryParseH3ControlStream(remoteAddr string, data []byte) {
	streamType, c0 := quicVarint(data)
	if c0 == 0 || streamType != 0x00 {
		return // not the h3 control stream
	}
	data = data[c0:]

	frameType, c1 := quicVarint(data)
	if c1 == 0 {
		return
	}
	data = data[c1:]

	frameLen, c2 := quicVarint(data)
	if c2 == 0 {
		return
	}
	data = data[c2:]

	// Per RFC 9114 §7.2.4: the first frame on the control stream MUST be SETTINGS.
	if frameType != 0x04 {
		return
	}
	if uint64(len(data)) < frameLen {
		return // truncated
	}
	body := data[:frameLen]

	settings := make(map[string]uint64)
	frameOrder := make([]uint64, 0, 8)
	for len(body) > 0 {
		id, ci := quicVarint(body)
		if ci == 0 {
			break
		}
		body = body[ci:]
		val, cv := quicVarint(body)
		if cv == 0 {
			break
		}
		body = body[cv:]
		settings[h3SettingName(id)] = val
		frameOrder = append(frameOrder, id)
	}

	sendFP(map[string]interface{}{
		"kind":        "h3_settings",
		"remote_addr": remoteAddr,
		"settings":    settings,
		"frame_order": frameOrder,
		"ts":          time.Now().UTC().Format(time.RFC3339),
	})
}

// quicVarint decodes an RFC 9000 §16 variable-length integer.
// Returns (value, bytes_consumed); bytes_consumed == 0 on failure.
func quicVarint(b []byte) (uint64, int) {
	if len(b) == 0 {
		return 0, 0
	}
	prefix := b[0] >> 6
	switch prefix {
	case 0:
		return uint64(b[0] & 0x3f), 1
	case 1:
		if len(b) < 2 {
			return 0, 0
		}
		return uint64(b[0]&0x3f)<<8 | uint64(b[1]), 2
	case 2:
		if len(b) < 4 {
			return 0, 0
		}
		return uint64(b[0]&0x3f)<<24 | uint64(b[1])<<16 | uint64(b[2])<<8 | uint64(b[3]), 4
	case 3:
		if len(b) < 8 {
			return 0, 0
		}
		return uint64(b[0]&0x3f)<<56 | uint64(b[1])<<48 | uint64(b[2])<<40 | uint64(b[3])<<32 |
			uint64(b[4])<<24 | uint64(b[5])<<16 | uint64(b[6])<<8 | uint64(b[7]), 8
	}
	return 0, 0
}

// h3SettingName maps RFC 9114 and extension SETTINGS IDs to human-readable names.
func h3SettingName(id uint64) string {
	switch id {
	case 0x01:
		return "QPACK_MAX_TABLE_CAPACITY"
	case 0x06:
		return "MAX_FIELD_SECTION_SIZE"
	case 0x07:
		return "QPACK_BLOCKED_STREAMS"
	case 0x08:
		return "ENABLE_CONNECT_PROTOCOL"
	case 0x33:
		return "H3_DATAGRAM"
	case 0xc671706a:
		return "ENABLE_WEBTRANSPORT"
	default:
		// GREASE values per RFC 9114 §7.2.8 pattern (0x1f * N + 0x21)
		if id > 0x20 && (id-0x21)%0x1f == 0 {
			return "GREASE"
		}
		return "UNKNOWN"
	}
}
