package main

import (
	"fmt"
	"net"
	"os"

	"github.com/pion/mediadevices"
	"github.com/pion/mediadevices/pkg/codec"
	"github.com/pion/mediadevices/pkg/codec/vpx"       // This is required to use VP8/VP9 video encoder
	_ "github.com/pion/mediadevices/pkg/driver/camera" // This is required to register camera adapter
	"github.com/pion/mediadevices/pkg/frame"
	"github.com/pion/mediadevices/pkg/prop"
	"github.com/pion/rtp"
	"github.com/pion/webrtc/v2"
	"github.com/pion/webrtc/v2/pkg/media"
)

const (
	mtu = 1000
)

func main() {
	if len(os.Args) != 2 {
		fmt.Printf("usage: %s host:port\n", os.Args[0])
		return
	}

	md := mediadevices.NewMediaDevicesFromCodecs(
		map[webrtc.RTPCodecType][]*webrtc.RTPCodec{
			webrtc.RTPCodecTypeVideo: []*webrtc.RTPCodec{
				webrtc.NewRTPVP8Codec(100, 90000),
			},
		},
		mediadevices.WithTrackGenerator(
			func(_ uint8, _ uint32, id, _ string, codec *webrtc.RTPCodec) (
				mediadevices.LocalTrack, error,
			) {
				return newTrack(codec, id, os.Args[1]), nil
			},
		),
	)

	vp8Params, err := vpx.NewVP8Params()
	if err != nil {
		panic(err)
	}
	vp8Params.BitRate = 100000 // 100kbps

	_, err = md.GetUserMedia(mediadevices.MediaStreamConstraints{
		Video: func(c *mediadevices.MediaTrackConstraints) {
			c.FrameFormat = prop.FrameFormat(frame.FormatYUY2)
			c.Enabled = true
			c.Width = prop.Int(640)
			c.Height = prop.Int(480)
			c.VideoEncoderBuilders = []codec.VideoEncoderBuilder{&vp8Params}
		},
	})
	if err != nil {
		panic(err)
	}

	select {}
}

type track struct {
	codec      *webrtc.RTPCodec
	packetizer rtp.Packetizer
	id         string
	conn       net.Conn
}

func newTrack(codec *webrtc.RTPCodec, id, dest string) *track {
	addr, err := net.ResolveUDPAddr("udp", dest)
	if err != nil {
		panic(err)
	}
	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		panic(err)
	}
	return &track{
		codec: codec,
		packetizer: rtp.NewPacketizer(
			mtu,
			codec.PayloadType,
			1,
			codec.Payloader,
			rtp.NewRandomSequencer(),
			codec.ClockRate,
		),
		id:   id,
		conn: conn,
	}
}

func (t *track) WriteSample(s media.Sample) error {
	buf := make([]byte, mtu)
	pkts := t.packetizer.Packetize(s.Data, s.Samples)
	for _, p := range pkts {
		n, err := p.MarshalTo(buf)
		if err != nil {
			panic(err)
		}
		_, _ = t.conn.Write(buf[:n])
	}
	return nil
}

func (t *track) Codec() *webrtc.RTPCodec {
	return t.codec
}

func (t *track) ID() string {
	return t.id
}

func (t *track) Kind() webrtc.RTPCodecType {
	return t.codec.Type
}
