package protokol

import (
	"bufio"
	"context"
	"encoding/json"
	"errors"
	"io"
	"testing"
	"time"
)

// yankiEsleMerhaba: merhaba'ya verilen cevabi taklit eder.
func yankiEsleMerhaba(okuyan io.Reader, yazan io.Writer, sonuc string) {
	go func() {
		r := bufio.NewReader(okuyan)
		for {
			m, err := Oku(r)
			if err != nil {
				return
			}
			c, _ := Cerceve(Mesaj{Id: m.Id, Result: json.RawMessage(sonuc)})
			if _, err := yazan.Write(c); err != nil {
				return
			}
		}
	}()
}

func TestElSikisBasarili(t *testing.T) {
	peerOku, istYaz := io.Pipe()
	istOku, peerYaz := io.Pipe()
	i := Yeni(istOku, istYaz, nil)
	defer i.Kapat()
	yankiEsleMerhaba(peerOku, peerYaz, `{"protokol":2,"eklenti":"ornek"}`)

	ctx, iptal := context.WithTimeout(context.Background(), 2*time.Second)
	defer iptal()
	ad, err := ElSikis(ctx, i, "0.4.0")
	if err != nil {
		t.Fatalf("el sikisma basarisiz: %v", err)
	}
	if ad != "ornek" {
		t.Fatalf("eklenti adi yanlis: %s", ad)
	}
}

func TestElSikisUyumsuzSurum(t *testing.T) {
	peerOku, istYaz := io.Pipe()
	istOku, peerYaz := io.Pipe()
	i := Yeni(istOku, istYaz, nil)
	defer i.Kapat()
	yankiEsleMerhaba(peerOku, peerYaz, `{"protokol":1,"eklenti":"eski"}`)

	ctx, iptal := context.WithTimeout(context.Background(), 2*time.Second)
	defer iptal()
	if _, err := ElSikis(ctx, i, "0.4.0"); !errors.Is(err, ErrProtokolUyumsuz) {
		t.Fatalf("ErrProtokolUyumsuz bekleniyordu: %v", err)
	}
}

func TestYanitlaKarsiTarafaGider(t *testing.T) {
	peerOku, istYaz := io.Pipe()
	istOku, _ := io.Pipe()
	i := Yeni(istOku, istYaz, nil)
	defer i.Kapat()

	sonuc := make(chan Mesaj, 1)
	go func() {
		m, _ := Oku(bufio.NewReader(peerOku))
		sonuc <- m
	}()
	if err := i.Yanitla(json.RawMessage("42"), map[string]bool{"izin": true}, nil); err != nil {
		t.Fatal(err)
	}
	select {
	case m := <-sonuc:
		if string(m.Id) != "42" || string(m.Result) != `{"izin":true}` {
			t.Fatalf("beklenmeyen cevap: %+v", m)
		}
	case <-time.After(2 * time.Second):
		t.Fatal("cevap karsi tarafa ulasmadi")
	}
}
