package tls

import (
	"bufio"
	"bytes"

	"github.com/9seconds/mtg/v2/essentials"
)

const (
	SizeRecordType = 1
	SizeVersion    = 2
	SizeSize       = 2
	SizeHeader     = SizeRecordType + SizeVersion + SizeSize

	MaxRecordSize        = 16384
	MaxRecordPayloadSize = MaxRecordSize - SizeHeader
	DefaultBufferSize    = 4096

	TypeChangeCipherSpec = 0x14
	TypeHandshake        = 0x16
	TypeApplicationData  = 0x17
)

// TLS 1.2 is used for both TLS 1.2 and 1.3
var TLSVersion = [SizeVersion]byte{3, 3}

// Conn presents an established TLS 1.3 connection, after handshake
type Conn struct {
	essentials.Conn

	p *connPayload
}

type connPayload struct {
	readBuf      bytes.Buffer
	connBuffered *bufio.Reader
	read         bool
	write        bool
}

func (c Conn) Write(p []byte) (int, error) {
	if !c.p.write {
		return c.Conn.Write(p)
	}

	return len(p), WriteRecord(c.Conn, p)
}

func (c Conn) Read(p []byte) (int, error) {
	if !c.p.read {
		return c.Conn.Read(p)
	}

	for {
		if n, err := c.p.readBuf.Read(p); err == nil {
			return n, nil
		}

		recordType, _, err := ReadRecord(c.p.connBuffered, &c.p.readBuf)
		if err != nil {
			return 0, err
		}

		if recordType != TypeApplicationData {
			c.p.readBuf.Reset()
		}
	}
}

func New(conn essentials.Conn, read, write bool) Conn {
	newConn := Conn{
		Conn: conn,
		p: &connPayload{
			connBuffered: bufio.NewReaderSize(conn, DefaultBufferSize),
			read:         read,
			write:        write,
		},
	}

	newConn.p.readBuf.Grow(DefaultBufferSize)

	return newConn
}
