package ktypes

import (
	"testing"
)

type testerOption struct {
	t *testing.T
}

func TestOption(t *testing.T) {
	sf := &testerOption{
		t: t,
	}
	sf.create()
}

// Создаёт новый Result
func (sf *testerOption) create() {
	sf.t.Log("create")
	sf.createSomeBad1()
	sf.createSomeGood1()
	sf.createSomeGood2()
	sf.createNoneGood1()
}

func (sf *testerOption) createNoneGood1() {
	sf.t.Log("createNoneGood1")
	defer func() {
		if _panic := recover(); _panic != nil {
			sf.t.Fatalf("createNoneGood1(): panic=%v", _panic)
		}
	}()
	res := NewNone[string]()
	if res.IsSome() {
		sf.t.Fatalf("createNoneGood1(): is ok")
	}
	if !res.IsNone() {
		sf.t.Fatalf("createNoneGood1(): not err")
	}
	if val := res.UnwrapOr("test2"); val != "test2" {
		sf.t.Fatalf("createNoneGood1(): val bad")
	}
	if val := res.UnwrapOr("test1"); val != "test1" {
		sf.t.Fatalf("createNoneGood1(): val bad")
	}
	if val := res.UnwrapOrFn(sf.fnWrap2); val != "test5" {
		sf.t.Fatalf("createNoneGood1(): val bad")
	}
	sf.unwrapErr(res)
	sf.hassert(res)
	sf.assert(res)
}

func (sf *testerOption) assert(res Option[string]) {
	sf.t.Log("assert")
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Fatalf("assert(): panic==nil")
		}
	}()
	res.Hassert("test assert")
}

func (sf *testerOption) hassert(res Option[string]) {
	sf.t.Log("hassert")
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Fatalf("hassert(): panic==nil")
		}
	}()
	res.Hassert("test hassert")
}

func (sf *testerOption) unwrapErr(res Option[string]) {
	sf.t.Log("unwrapErr")
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Fatalf("unwrapErr(): panic==nil")
		}
	}()
	_ = res.Unwrap()
}

func (sf *testerOption) createSomeGood2() {
	sf.t.Log("createSomeGood2")
	defer func() {
		if _panic := recover(); _panic != nil {
			sf.t.Fatalf("createSomeGood2(): panic=%v", _panic)
		}
	}()
	str := "test val"
	res := NewSome(str)
	if !res.IsSome() {
		sf.t.Fatalf("createSomeGood1(): not ok")
	}
	if res.IsNone() {
		sf.t.Fatalf("createSomeGood1(): is err")
	}
	if val := res.Unwrap(); val != "test val" {
		sf.t.Fatalf("createSomeGood1(): val bad")
	}
	if val := res.UnwrapOr("test1"); val != "test val" {
		sf.t.Fatalf("createSomeGood1(): val bad")
	}
	if val := res.UnwrapOr("test1"); val != "test val" {
		sf.t.Fatalf("createSomeGood1(): val bad")
	}
	if val := res.UnwrapOrFn(sf.fnWrap); val != "test val" {
		sf.t.Fatalf("createSomeGood1(): val bad")
	}
	res.Hassert("test")
	res.Assert("test")
}

// Функция высшего порядка для замещения ошибки
func (sf *testerOption) fnWrap2() string {
	return "test5"
}

// Функция высшего порядка для замещения ошибки
func (sf *testerOption) fnWrap() string {
	return "test1"
}

func (sf *testerOption) createSomeGood1() {
	sf.t.Log("createSomeGood1")
	defer func() {
		if _panic := recover(); _panic != nil {
			sf.t.Fatalf("createSomeGood1(): panic=%v", _panic)
		}
	}()
	str := "test val"
	_ = NewSome(&str)
}

// Нет результата
func (sf *testerOption) createSomeBad1() {
	sf.t.Log("createSomeBad1")
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Fatalf("createSomeBad1(): panic==nil")
		}
	}()
	var str *string
	_ = NewSome(str)
}
