package admin

import (
	"context"
	"fmt"
	"net/http"
	"time"

	_ "embed"

	"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
	"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
	"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
	"github.com/FAU-CDI/wisski-distillery/internal/status"
	"golang.org/x/sync/errgroup"
)

// Status produces a new observation of the distillery, and a new information of all instances
// The information on all instances is passed the given quick flag.
func (admin *Admin) Status(ctx context.Context, QuickInformation bool) (target status.Distillery, information []status.WissKI, err error) {
	var group errgroup.Group

	group.Go(func() error {
		// list all the instances
		all, err := admin.dependencies.Instances.All(ctx)
		if err != nil {
			return err
		}

		// get all of their info!
		information = make([]status.WissKI, len(all))
		for i, instance := range all {
			{
				i := i
				instance := instance

				// store the info for this group!
				group.Go(func() (err error) {
					information[i], err = instance.Info().Information(ctx, true)
					if err != nil {
						return fmt.Errorf("instance %q: %w", instance.Slug, err)
					}
					return
				})
			}
		}
		return nil
	})

	// gather all the observations
	flags := component.FetcherFlags{
		Context: ctx,
	}
	for _, o := range admin.dependencies.Fetchers {
		o := o
		group.Go(func() error {
			return o.Fetch(flags, &target)
		})
	}

	// wait for all the fetchers to finish
	if err := group.Wait(); err != nil {
		return status.Distillery{}, nil, err
	}

	// count overall instances
	for _, i := range information {
		if i.Running {
			target.RunningCount++
		} else {
			target.StoppedCount++
		}
	}
	target.TotalCount = len(information)

	return
}

func (admin *Admin) Fetch(flags component.FetcherFlags, target *status.Distillery) error {
	target.Time = time.Now().UTC()
	target.Config = component.GetStill(admin).Config
	return nil
}

//go:embed "html/index.html"
var indexHTML []byte
var indexTemplate = templating.Parse[indexContext](
	"index.html", indexHTML, nil,

	templating.Title("Admin"),
	templating.Assets(assets.AssetsAdmin),

	templating.Crumbs(
		menuAdmin,
	),
)

//go:embed "html/instances.html"
var instancesHTML []byte
var instancesTemplate = templating.Parse[indexContext](
	"instances.html", instancesHTML, nil,

	templating.Title("Instances"),
	templating.Assets(assets.AssetsAdmin),
)

type indexContext struct {
	templating.RuntimeFlags

	status.Distillery
	Instances []status.WissKI
}

func (admin *Admin) index(context.Context) http.Handler {
	tpl := indexTemplate.Prepare(
		admin.dependencies.Templating,
		templating.Actions(
			menuUsers,
			menuInstances,
		),
	)

	return tpl.HTMLHandler(admin.dependencies.Handling, func(r *http.Request) (idx indexContext, err error) {
		idx.Distillery, idx.Instances, err = admin.Status(r.Context(), false)
		return
	})
}

func (admin *Admin) instances(context.Context) http.Handler {
	tpl := instancesTemplate.Prepare(
		admin.dependencies.Templating,
		templating.Crumbs(
			menuAdmin,
			menuInstances,
		),
		templating.Actions(
			menuProvision,
		),
	)

	return tpl.HTMLHandler(admin.dependencies.Handling, func(r *http.Request) (idx indexContext, err error) {
		idx.Distillery, idx.Instances, err = admin.Status(r.Context(), true)
		return
	})
}
