package esr

import (
	"esr/internal/config"
	"fmt"

	"github.com/evanw/esbuild/pkg/api"
)

type Esr struct {
	Config  *config.Config
	Builder *Builder
	Server  *Server
	Runner  *Runner
}

func NewEsr(c *config.Config, entryPoint string) *Esr {
	builder := NewBuilder(c, entryPoint)
	server := NewDevServer(c, entryPoint, builder)

	return &Esr{
		Config:  c,
		Builder: builder,
		Server:  server,
		Runner:  NewRunner(c, builder, entryPoint),
	}
}

func ExecuteTask(esr *Esr, build, serve, run, watch bool) {
	entryPoint := esr.Builder.EntryPoint

	if build {
		opts := ModeOptions(esr.Config, ModeBuilder, entryPoint, "")
		if err := esr.Builder.Build(opts); err != nil {
			fmt.Println("Build error:", err)
			return
		}
	}

	if serve {
		opts := ModeOptions(esr.Config, ModeServer, entryPoint, "")
		if err := esr.Builder.Build(opts); err != nil {
			fmt.Println("Build before serve error:", err)
			return
		}
		startServerWithWatching(esr, opts)
	}

	if run {
		esr.Runner.Run(entryPoint)
	}

	if watch && !(serve || run) {
		opts := ModeOptions(esr.Config, ModeServer, entryPoint, "")
		err := esr.Builder.StartWatch(opts, esr.generalCallback(run, entryPoint))
		if err != nil {
			fmt.Println("Watch error:", err)
		}
	}
}

func startServerWithWatching(esr *Esr, opts *api.BuildOptions) {
	err := esr.Builder.StartWatch(opts, esr.serveCallback())
	if err != nil {
		fmt.Println("Server watch error:", err)
	}

	if err := esr.Server.Start(); err != nil {
		fmt.Println("Server error:", err)
	}
}

func (esr *Esr) generalCallback(run bool, entryPoint string) func() {
	return func() {
		if run {
			esr.Runner.Run(entryPoint)
		}
	}
}

func (esr *Esr) serveCallback() func() {
	return func() {
		esr.Server.LiveReload.Reload()
	}
}
