package sctp

import (
	"context"
	"sync"
	"time"
)

func (c *Client) handshake(ctx context.Context, addr *Addr, initiator bool, timeout time.Duration) error {
	wg := &sync.WaitGroup{}
	wg.Add(2)

	udpAddr, err := addr.UDPAddr()
	if err != nil {
		return err
	}

	var writeErr error
	var readErr error
	send := "syn"
	go func() {
		for {
			if _, err := c.conn.WriteToUDP([]byte(send), udpAddr); err != nil {
				writeErr = err
				break
			}
			if send == "ack" {
				break
			}
			time.Sleep(time.Millisecond * 100)
		}
		wg.Done()
	}()

	read := true
	go func() {
	ReadLoop:
		for read {
			b, err := c.readFromUDP()
			if err != nil {
				readErr = err
				break
			}
			switch string(b) {
			case "syn":
				// logger.Debugf("SCTP syn")
				send = "syn-ack"
			case "syn-ack":
				// logger.Debugf("SCTP syn-ack")
				send = "ack"
				// Established on syn-ack for client
				if initiator {
					break ReadLoop
				}
			case "ack":
				// logger.Debugf("SCTP ack")
				// Established on ack for server
				send = "ack"
				break ReadLoop
			}
		}
		wg.Done()
	}()

	ch := make(chan struct{})
	go func() {
		logger.Debugf("Wait for (sctp) handshake...")
		wg.Wait()
		close(ch)
	}()

	select {
	case <-ch:
	case <-ctx.Done():
		return ctx.Err()
	case <-time.After(timeout):
		logger.Debugf("SCTP handshake timed out")
		return ErrHandshakeTimeout
	}

	if writeErr != nil {
		return writeErr
	}
	if readErr != nil {
		return readErr
	}

	logger.Infof("SCTP handshake done")

	return nil
}
