package ktypes

import (
	"fmt"
	"runtime"
	"testing"
)

type testerResult struct {
	t *testing.T
}

func TestResult(t *testing.T) {
	sf := &testerResult{
		t: t,
	}
	sf.create()
	sf.notCheck()

}

// Создаёт новый результат и не проверяет его
func (sf *testerResult) notCheck() {
	sf.t.Log("notCheck")
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Fatalf("notCheck(): panic==nil")
		}
	}()
	res := NewOk("test")
	{
		val := res.Val()
		if val != "test" {
			sf.t.Fatalf("notCheck() test!=test")
		}
	}
	runtime.Gosched()
	runtime.GC()
	res.destroy(&res)
}

// Создаёт новый Result
func (sf *testerResult) create() {
	sf.t.Log("create")
	sf.createOkBad1()
	sf.createOkGood1()
	sf.createOkGood2()
	sf.createErrBad1()
	sf.createErrGood1()
}

func (sf *testerResult) createErrGood1() {
	sf.t.Log("createErrGood1")
	defer func() {
		if _panic := recover(); _panic != nil {
			sf.t.Fatalf("createErrGood1(): panic=%v", _panic)
		}
	}()
	err := fmt.Errorf("test err")
	res := NewErr[string](err)
	if res.IsOk() {
		sf.t.Fatalf("createErrGood1(): is ok")
	}
	if !res.IsErr() {
		sf.t.Fatalf("createErrGood1(): not err")
	}
	if val := res.ValOr("test2"); val != "test2" {
		sf.t.Fatalf("createErrGood1(): val bad")
	}
	if val := res.ValOr("test1"); val != "test1" {
		sf.t.Fatalf("createErrGood1(): val bad")
	}
	if val := res.ValOrFn(sf.fnWrap2); val != "test5" {
		sf.t.Fatalf("createErrGood1(): val bad")
	}
	if err := res.Err(); err == nil {
		sf.t.Fatalf("createErrGood1(): err == nil")
	}
	{
		res0 := WrapErr(res, err)
		if res0.IsOk() {
			sf.t.Fatalf("createErrGood1(): err == nil")
		}
		_ = res0.Error()
	}
	{
		res := NewOk("test_ok")
		if val := res.ValOr("test_ok1"); val != "test_ok" {
			sf.t.Fatalf("createErrGood1(): val(%v) != 'test_ok'", val)
		}
	}
	sf.unwrapErr(res)
	sf.hassert(res)
	sf.hassert2(res)
	sf.assert2()
}

func (sf *testerResult) assert2() {
	sf.t.Log("assert2")
	err := fmt.Errorf("test_error")
	res := NewErr[bool](err)
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Fatalf("assert2(): panic==nil")
		}
	}()
	res.Assert("test assert2")
}

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

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

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

// Нет ошибки
func (sf *testerResult) createErrBad1() {
	sf.t.Log("createErrBad1")
	defer func() {
		if _panic := recover(); _panic == nil {
			sf.t.Fatalf("createErrBad1(): panic==nil")
		}
	}()
	var err error
	_ = NewErr[bool](err)
}

func (sf *testerResult) createOkGood2() {
	sf.t.Log("createOkGood2")
	defer func() {
		if _panic := recover(); _panic != nil {
			sf.t.Fatalf("createOkGood2(): panic=%v", _panic)
		}
	}()
	str := "test val"
	res := NewOk(str)
	if !res.IsOk() {
		sf.t.Fatalf("createOkGood1(): not ok")
	}
	if res.IsErr() {
		sf.t.Fatalf("createOkGood1(): is err")
	}
	if val := res.Val(); val != "test val" {
		sf.t.Fatalf("createOkGood1(): val bad")
	}
	if val := res.ValOr("test1"); val != "test val" {
		sf.t.Fatalf("createOkGood1(): val bad")
	}
	if val := res.ValOr("test1"); val != "test val" {
		sf.t.Fatalf("createOkGood1(): val bad")
	}
	if val := res.ValOrFn(sf.fnWrap); val != "test val" {
		sf.t.Fatalf("createOkGood1(): val bad")
	}
	res0 := NewErr[any](fmt.Errorf("test_error"))
	if err := res0.Err(); err == nil {
		sf.t.Fatalf("createOkGood1(): err ==nil")
	}
	res.Hassert("test")
	res.Assert("test")
}

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

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

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

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