// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0

package validation

import (
	"context"

	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

	capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
	ad "github.com/projectcapsule/capsule/pkg/runtime/admission"
	"github.com/projectcapsule/capsule/pkg/runtime/configuration"
	"github.com/projectcapsule/capsule/pkg/runtime/events"
	"github.com/projectcapsule/capsule/pkg/runtime/handlers"
)

func Handler(configuration configuration.Configuration, handlers ...handlers.TypedHandler[*capsulev1beta2.Tenant]) handlers.Handler {
	return &handler{
		cfg:      configuration,
		handlers: handlers,
	}
}

type handler struct {
	cfg      configuration.Configuration
	handlers []handlers.TypedHandler[*capsulev1beta2.Tenant]
}

func (h *handler) OnCreate(
	c client.Client,
	reader client.Reader,
	decoder admission.Decoder,
	recorder events.EventRecorder,
) handlers.Func {
	return func(ctx context.Context, req admission.Request) *admission.Response {
		tnt := &capsulev1beta2.Tenant{}
		if err := decoder.Decode(req, tnt); err != nil {
			return ad.ErroredResponse(err)
		}

		for _, hndl := range h.handlers {
			if response := hndl.OnCreate(c, reader, tnt, decoder, recorder)(ctx, req); response != nil {
				return response
			}
		}

		return nil
	}
}

func (h *handler) OnDelete(
	c client.Client,
	reader client.Reader,
	decoder admission.Decoder,
	recorder events.EventRecorder,
) handlers.Func {
	return func(ctx context.Context, req admission.Request) *admission.Response {
		tnt := &capsulev1beta2.Tenant{}
		if err := decoder.DecodeRaw(req.OldObject, tnt); err != nil {
			return ad.ErroredResponse(err)
		}

		for _, hndl := range h.handlers {
			if response := hndl.OnDelete(c, reader, tnt, decoder, recorder)(ctx, req); response != nil {
				return response
			}
		}

		return nil
	}
}

func (h *handler) OnUpdate(
	c client.Client,
	reader client.Reader,
	decoder admission.Decoder,
	recorder events.EventRecorder,
) handlers.Func {
	return func(ctx context.Context, req admission.Request) *admission.Response {
		tnt := &capsulev1beta2.Tenant{}
		if err := decoder.Decode(req, tnt); err != nil {
			return ad.ErroredResponse(err)
		}

		old := &capsulev1beta2.Tenant{}
		if err := decoder.DecodeRaw(req.OldObject, old); err != nil {
			return ad.ErroredResponse(err)
		}

		for _, hndl := range h.handlers {
			if response := hndl.OnUpdate(c, reader, tnt, old, decoder, recorder)(ctx, req); response != nil {
				return response
			}
		}

		return nil
	}
}
