package webtorrent

import (
	"encoding/base64"
	"fmt"
	"strconv"
	"time"

	"github.com/AlexxIT/go2rtc/pkg/core"
	"github.com/AlexxIT/go2rtc/pkg/webrtc"
	"github.com/gorilla/websocket"
	pion "github.com/pion/webrtc/v4"
)

func NewClient(tracker, share, pwd string, pc *pion.PeerConnection) (*webrtc.Conn, error) {
	// 1. Create WebRTC producer
	prod := webrtc.NewConn(pc)
	prod.FormatName = "webtorrent"
	prod.Mode = core.ModeActiveProducer
	prod.Protocol = "ws"

	medias := []*core.Media{
		{Kind: core.KindVideo, Direction: core.DirectionRecvonly},
		{Kind: core.KindAudio, Direction: core.DirectionRecvonly},
	}

	// 2. Create offer
	offer, err := prod.CreateCompleteOffer(medias)
	if err != nil {
		return nil, err
	}

	// 3. Encrypt offer
	nonce := strconv.FormatInt(time.Now().UnixNano(), 36)

	cipher, err := NewCipher(share, pwd, nonce)
	if err != nil {
		return nil, err
	}

	enc := cipher.Encrypt([]byte(offer))

	// 4. Connect to Tracker
	ws, _, err := websocket.DefaultDialer.Dial(tracker, nil)
	if err != nil {
		return nil, err
	}

	defer ws.Close()

	// 5. Send offer
	msg := fmt.Sprintf(
		`{"action":"announce","info_hash":"%s","peer_id":"%s","offers":[{"offer_id":"%s","offer":{"type":"offer","sdp":"%s"}}],"numwant":1}`,
		InfoHash(share), core.RandString(16, 36), nonce, base64.StdEncoding.EncodeToString(enc),
	)
	if err = ws.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
		return nil, err
	}

	// wait 30 seconds until full answer
	if err = ws.SetReadDeadline(time.Now().Add(time.Second * 30)); err != nil {
		return nil, err
	}

	for {
		// 6. Read answer
		var v Message
		if err = ws.ReadJSON(&v); err != nil {
			return nil, err
		}

		if v.Answer == nil {
			continue
		}

		// 7. Decrypt answer
		enc, err = base64.StdEncoding.DecodeString(v.Answer.SDP)
		if err != nil {
			return nil, err
		}

		answer, err := cipher.Decrypt(enc)
		if err != nil {
			return nil, err
		}

		// 8. Set answer
		if err = prod.SetAnswer(string(answer)); err != nil {
			return nil, err
		}

		return prod, nil
	}
}
