package server

import (
	"fmt"
	"os"
	"time"

	"git.ctrlz.es/mgdelacroix/craban/api"
	"git.ctrlz.es/mgdelacroix/craban/app"
	"git.ctrlz.es/mgdelacroix/craban/model"
	"git.ctrlz.es/mgdelacroix/craban/services/store"
	"git.ctrlz.es/mgdelacroix/craban/web"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

func init() {
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339})
	log.Logger = log.With().Caller().Logger()
}

type Server struct {
	Config *model.Config

	App       *app.App
	API       *api.API
	Store     *store.Store
	WebServer *web.WebServer
}

func NewServer(config *model.Config) (*Server, error) {
	if err := config.IsValid(); err != nil {
		return nil, fmt.Errorf("config is not valid: %w", err)
	}

	webserver, err := web.NewWebServer(*config.Port)
	if err != nil {
		return nil, fmt.Errorf("cannot create webserver: %w", err)
	}
	log.Debug().Msg("webserver created")

	store, err := store.NewStore(*config.DatabasePath)
	if err != nil {
		return nil, fmt.Errorf("cannot create store: %w", err)
	}
	log.Debug().Msg("store created")

	app := app.NewApp(config, store)
	log.Debug().Msg("app created")
	api := api.NewAPI(app)
	log.Debug().Msg("API created")
	webserver.RegisterRoutes(api)
	log.Debug().Msg("webserver routes registered with the API")

	return &Server{
		Config:    config,
		WebServer: webserver,
		App:       app,
		API:       api,
		Store:     store,
	}, err
}

func NewServerWithConfigPath(path string) (*Server, error) {
	config, err := model.ReadConfig(path)
	if err != nil {
		return nil, fmt.Errorf("cannot read config from path %q: %w", path, err)
	}

	return NewServer(config)
}

func (s *Server) Start() error {
	log.Debug().Msg("starting server")
	if err := s.WebServer.Start(); err != nil {
		return fmt.Errorf("error starting webserver: %w", err)
	}
	return nil
}

func (s *Server) Close() error {
	log.Debug().Msg("closing server")
	if err := s.WebServer.Close(); err != nil {
		return fmt.Errorf("error stopping webserver: %w", err)
	}

	if err := s.Store.Close(); err != nil {
		return fmt.Errorf("error stopping store: %w", err)
	}

	log.Debug().Msg("server closed")
	return nil
}
