// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package provider

import (
	"context"

	corev1 "k8s.io/api/core/v1"
	discoveryv1 "k8s.io/api/discovery/v1"
	k8stypes "k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"

	"github.com/apache/apisix-ingress-controller/api/v1alpha1"
	apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
	"github.com/apache/apisix-ingress-controller/internal/controller/status"
	"github.com/apache/apisix-ingress-controller/internal/types"
)

type Provider interface {
	RegisterHandler
	Update(context.Context, *TranslateContext, client.Object) error
	Delete(context.Context, client.Object) error
	Start(context.Context) error
	NeedLeaderElection() bool
}

type TranslateContext struct {
	context.Context
	RouteParentRefs  []gatewayv1.ParentReference
	BackendRefs      []gatewayv1.BackendRef
	GatewayTLSConfig []gatewayv1.ListenerTLSConfig
	Credentials      []v1alpha1.Credential
	Listeners        []gatewayv1.Listener
	// HasExplicitListenerMatch is true when any accepted parentRef attached to
	// its Gateway through an explicit sectionName or port. It gates server_port
	// injection (see Translator.shouldInjectServerPortVars) and is computed from
	// the matched RouteParentRefContext, preserving each parentRef's Gateway.
	HasExplicitListenerMatch bool

	EndpointSlices         map[k8stypes.NamespacedName][]discoveryv1.EndpointSlice
	Secrets                map[k8stypes.NamespacedName]*corev1.Secret
	ConfigMaps             map[k8stypes.NamespacedName]*corev1.ConfigMap
	PluginConfigs          map[k8stypes.NamespacedName]*v1alpha1.PluginConfig
	ApisixPluginConfigs    map[k8stypes.NamespacedName]*apiv2.ApisixPluginConfig
	Services               map[k8stypes.NamespacedName]*corev1.Service
	BackendTrafficPolicies map[k8stypes.NamespacedName]*v1alpha1.BackendTrafficPolicy
	L4RoutePolicies        map[k8stypes.NamespacedName]*v1alpha1.L4RoutePolicy
	Upstreams              map[k8stypes.NamespacedName]*apiv2.ApisixUpstream
	GatewayProxies         map[types.NamespacedNameKind]v1alpha1.GatewayProxy
	ResourceParentRefs     map[types.NamespacedNameKind][]types.NamespacedNameKind
	// GatewayProxyReferrers key is GatewayProxy, value is a list of resources that reference this GatewayProxy
	GatewayProxyReferrers map[k8stypes.NamespacedName][]types.NamespacedNameKind
	HTTPRoutePolicies     []v1alpha1.HTTPRoutePolicy

	StatusUpdaters []status.Update
}

func NewDefaultTranslateContext(ctx context.Context) *TranslateContext {
	return &TranslateContext{
		Context:                ctx,
		EndpointSlices:         make(map[k8stypes.NamespacedName][]discoveryv1.EndpointSlice),
		Secrets:                make(map[k8stypes.NamespacedName]*corev1.Secret),
		ConfigMaps:             make(map[k8stypes.NamespacedName]*corev1.ConfigMap),
		PluginConfigs:          make(map[k8stypes.NamespacedName]*v1alpha1.PluginConfig),
		ApisixPluginConfigs:    make(map[k8stypes.NamespacedName]*apiv2.ApisixPluginConfig),
		Services:               make(map[k8stypes.NamespacedName]*corev1.Service),
		BackendTrafficPolicies: make(map[k8stypes.NamespacedName]*v1alpha1.BackendTrafficPolicy),
		L4RoutePolicies:        make(map[k8stypes.NamespacedName]*v1alpha1.L4RoutePolicy),
		Upstreams:              make(map[k8stypes.NamespacedName]*apiv2.ApisixUpstream),
		GatewayProxies:         make(map[types.NamespacedNameKind]v1alpha1.GatewayProxy),
		ResourceParentRefs:     make(map[types.NamespacedNameKind][]types.NamespacedNameKind),
		GatewayProxyReferrers:  make(map[k8stypes.NamespacedName][]types.NamespacedNameKind),
	}
}
