package rest

import (
	"io"

	"git.ali33.ru/fcg-xvii/go-tools/json"
)

type (
	RequestType         byte
	RequestFiles        map[string]IReadCloserLen
	TokenGenerateMethod func(data json.Map, expire int64) (string, error)
)

const (
	RequestTypeIn RequestType = iota
	RequestTypeOut
	RequestTypeEvent
)

type IRequest interface {
	RType() RequestType
	RCommand() string
	RData() json.Map
	RFiles() RequestFiles
	RFile(string) (IReadCloserLen, bool)
	RClose()
	Fields(any, RequestFiles) (json.Map, IErrorArgs)
}

////////////////////////////////////////////

type Request struct {
	Type    RequestType
	Command string
	Data    json.Map
	Files   RequestFiles
}

func (s *Request) RType() RequestType {
	return s.Type
}

func (s *Request) RCommand() string {
	return s.Command
}

func (s *Request) RData() json.Map {
	if s.Data == nil {
		return json.Map{}
	}
	return s.Data
}

func (s *Request) RFiles() RequestFiles {
	return s.Files
}

func (s *Request) RFile(name string) (IReadCloserLen, bool) {
	res, check := s.Files[name]
	return res, check
}

func (s *Request) RClose() {
	for _, file := range s.Files {
		file.Close()
	}
	s.Files = nil
}

func (s *Request) Fields(obj any, files RequestFiles) (json.Map, IErrorArgs) {
	return Fields(obj, files, s.Data.Slice("fields", nil)...)
}

////////////////////////////////////////////////////////////

type IRequestIn interface {
	IRequest
	Auth() json.Map
	SetAuth(json.Map)
	GenerateToken(data json.Map, expire int64) (string, error)
	ROwner() IOwner
	RCore() any
	OutSuccess(data json.Map, files RequestFiles) IRequestOut
	OutError(err IErrorArgs) IRequestOut
	ClientData(key string) (any, bool)
	SetClientData(key string, data any)
}

type RequestIn struct {
	IRequest
	Owner          IOwner
	Core           any
	GeneratorToken TokenGenerateMethod
}

func (s *RequestIn) Auth() json.Map {
	if store, check := s.Owner.(IStream); check {
		return store.Auth()
	}
	return nil
}

func (s *RequestIn) SetAuth(auth json.Map) {
	if store, check := s.Owner.(IStream); check {
		store.SetAuth(auth)
	}
}

func (s *RequestIn) GenerateToken(data json.Map, expire int64) (string, error) {
	return s.GeneratorToken(data, expire)
}

func (s *RequestIn) ClientData(key string) (any, bool) {
	if store, check := s.Owner.(IStream); check {
		return store.ClientData(key)
	}
	return nil, false
}

func (s *RequestIn) SetClientData(key string, data any) {
	if store, check := s.Owner.(IStream); check {
		store.SetClientData(key, data)
	}
}

func (s *RequestIn) ROwner() IOwner {
	return s.Owner
}

func (s *RequestIn) RCore() any {
	return s.Core
}

/////////////////////////////////////////////////////////

type IRequestOut interface {
	IRequest
	Write(io.Writer) IErrorArgs
}