package microservice

import (
	"context"
	"fmt"
	"log"
	"net"

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

func NewServer(host string, port uint16, sockBufSize int, ctx context.Context) *Server {
	ctx, cancel := context.WithCancel(ctx)
	server := &Server{
		ctx:          ctx,
		cancel:       cancel,
		host:         host,
		port:         port,
		chConnection: make(chan *Socket),
		sockets:      concurrent.NewList(),
	}
	go server.start()
	return server
}

type Server struct {
	ctx          context.Context
	cancel       context.CancelFunc
	host         string
	port         uint16
	sockBufSize  int
	listener     net.Listener
	sockets      *concurrent.List
	chConnection chan *Socket
}

func (s *Server) NewConnection() <-chan *Socket {
	return s.chConnection
}

func (s *Server) start() {
	go s.listen()
	<-s.ctx.Done()
	s.listener.Close()
	close(s.chConnection)
}

func (s *Server) listen() {
	var err error
	if s.listener, err = net.Listen("tcp", fmt.Sprintf("%v:%v", s.host, s.port)); err != nil {
		log.Fatal("Error starting all trade server:", err)
	}
	var conn net.Conn
	for {
		if conn, err = s.listener.Accept(); err != nil {
			//fmt.Println("Error accepting connection:", err)
			return
		}
		socket := NewSocket(conn, s.sockBufSize, s.ctx)
		s.sockets.PushBack(socket)
		go func(sock *Socket) {
			<-sock.Context().Done()
			log.Println("close sock accepted....")
			if elem := s.sockets.Search(sock); elem != nil {
				log.Println("socket remove from list")
				s.sockets.Remove(elem)
			}
			log.Println(s.sockets.Size())
		}(socket)
		s.chConnection <- socket
	}
}

func (s *Server) Close() {
	s.cancel()
	s.sockets.Each(func(val *concurrent.Element) bool {
		log.Println("CLOSE socket..........")
		val.Val().(*Socket).Close()
		return true
	})
}