package aoiprxkit

import (
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)

type SDPInfo struct {
	SessionName    string
	Origin         string
	MulticastGroup string
	Port           int
	PayloadType    uint8
	Encoding       string
	SampleRateHz   int
	Channels       int
	PacketTimeMS   int
}

// ParseMinimalSDP extracts the multicast address, port and one rtpmap line.
// It is deliberately small and not a full SDP parser.
func ParseMinimalSDP(s string) (SDPInfo, error) {
	var out SDPInfo
	lines := strings.Split(strings.ReplaceAll(s, "\r\n", "\n"), "\n")
	for _, raw := range lines {
		line := strings.TrimSpace(raw)
		switch {
		case strings.HasPrefix(line, "s="):
			out.SessionName = strings.TrimPrefix(line, "s=")

		case strings.HasPrefix(line, "o="):
			out.Origin = strings.TrimPrefix(line, "o=")

		case strings.HasPrefix(line, "c=IN IP4 "):
			rest := strings.TrimPrefix(line, "c=IN IP4 ")
			host := strings.Split(rest, "/")[0]
			if net.ParseIP(host) == nil {
				return out, fmt.Errorf("invalid multicast host in c=: %q", host)
			}
			out.MulticastGroup = host

		case strings.HasPrefix(line, "m=audio "):
			fields := strings.Fields(line)
			if len(fields) < 4 {
				return out, fmt.Errorf("invalid m=audio line")
			}
			port, err := strconv.Atoi(fields[1])
			if err != nil {
				return out, fmt.Errorf("invalid audio port: %w", err)
			}
			pt, err := strconv.Atoi(fields[3])
			if err != nil {
				return out, fmt.Errorf("invalid payload type: %w", err)
			}
			out.Port = port
			out.PayloadType = uint8(pt)

		case strings.HasPrefix(line, "a=rtpmap:"):
			rest := strings.TrimPrefix(line, "a=rtpmap:")
			parts := strings.Fields(rest)
			if len(parts) != 2 {
				return out, fmt.Errorf("invalid rtpmap line")
			}
			pt, err := strconv.Atoi(parts[0])
			if err != nil {
				return out, fmt.Errorf("invalid rtpmap payload type: %w", err)
			}
			codecParts := strings.Split(parts[1], "/")
			if len(codecParts) < 2 {
				return out, fmt.Errorf("invalid rtpmap codec tuple")
			}
			sr, err := strconv.Atoi(codecParts[1])
			if err != nil {
				return out, fmt.Errorf("invalid rtpmap sample rate: %w", err)
			}
			ch := 1
			if len(codecParts) >= 3 {
				ch, err = strconv.Atoi(codecParts[2])
				if err != nil {
					return out, fmt.Errorf("invalid rtpmap channel count: %w", err)
				}
			}
			out.PayloadType = uint8(pt)
			out.Encoding = codecParts[0]
			out.SampleRateHz = sr
			out.Channels = ch

		case strings.HasPrefix(line, "a=ptime:"):
			ms, err := strconv.Atoi(strings.TrimPrefix(line, "a=ptime:"))
			if err == nil {
				out.PacketTimeMS = ms
			}
		}
	}
	if out.MulticastGroup == "" || out.Port == 0 || out.Encoding == "" || out.SampleRateHz == 0 {
		return out, fmt.Errorf("incomplete SDP: %+v", out)
	}
	return out, nil
}

func ConfigFromSDP(base Config, info SDPInfo) (Config, error) {
	cfg := base
	cfg.MulticastGroup = info.MulticastGroup
	cfg.Port = info.Port
	cfg.PayloadType = info.PayloadType
	cfg.SampleRateHz = info.SampleRateHz
	cfg.Channels = info.Channels
	cfg.Encoding = info.Encoding
	if info.PacketTimeMS > 0 {
		cfg.PacketTime = time.Duration(info.PacketTimeMS) * time.Millisecond
	}
	return cfg, cfg.Validate()
}
