// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s

package render

import (
	"fmt"
	"strings"
	"time"

	"github.com/derailed/k9s/internal/client"
	"github.com/derailed/k9s/internal/model1"
	"github.com/derailed/tcell/v2"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// Forwarder represents a port forwarder.
type Forwarder interface {
	// ID returns the PF FQN.
	ID() string

	// Container returns a container name.
	Container() string

	// Port returns container exposed port.
	Port() string

	// Address returns the host address.
	Address() string

	// Active returns forwarder current state.
	Active() bool

	// Age returns forwarder age.
	Age() time.Time
}

// PortForward renders a portforwards to screen.
type PortForward struct {
	Base
}

// ColorerFunc colors a resource row.
func (PortForward) ColorerFunc() model1.ColorerFunc {
	return func(string, model1.Header, *model1.RowEvent) tcell.Color {
		return tcell.ColorSkyblue
	}
}

// Header returns a header row.
func (PortForward) Header(string) model1.Header {
	return model1.Header{
		model1.HeaderColumn{Name: "NAMESPACE"},
		model1.HeaderColumn{Name: "NAME"},
		model1.HeaderColumn{Name: "CONTAINER"},
		model1.HeaderColumn{Name: "PORTS"},
		model1.HeaderColumn{Name: "URL"},
		model1.HeaderColumn{Name: "C"},
		model1.HeaderColumn{Name: "N"},
		model1.HeaderColumn{Name: "VALID", Attrs: model1.Attrs{Wide: true}},
		model1.HeaderColumn{Name: "AGE", Attrs: model1.Attrs{Time: true}},
	}
}

// Render renders a K8s resource to screen.
func (PortForward) Render(o any, _ string, r *model1.Row) error {
	pf, ok := o.(ForwardRes)
	if !ok {
		return fmt.Errorf("expecting a ForwardRes but got %T", o)
	}

	ports := strings.Split(pf.Port(), ":")
	r.ID = pf.ID()
	ns, n := client.Namespaced(r.ID)

	r.Fields = model1.Fields{
		ns,
		trimContainer(n),
		pf.Container(),
		pf.Port(),
		UrlFor(pf.Config.Host, pf.Config.Path, ports[0], pf.Address()),
		AsThousands(int64(pf.Config.C)),
		AsThousands(int64(pf.Config.N)),
		"",
		ToAge(metav1.Time{Time: pf.Age()}),
	}

	return nil
}

// Helpers...

func trimContainer(n string) string {
	tokens := strings.Split(n, "|")
	if len(tokens) == 0 {
		return n
	}
	_, name := client.Namespaced(tokens[0])

	return name
}

// UrlFor computes fq url for a given benchmark configuration.
func UrlFor(host, path, port, address string) string {
	if host == "" {
		host = address
	}
	if path == "" {
		path = "/"
	}

	return "http://" + host + ":" + port + path
}

// BenchCfg represents a benchmark configuration.
type BenchCfg struct {
	C, N       int
	Host, Path string
}

// ForwardRes represents a benchmark resource.
type ForwardRes struct {
	Forwarder
	Config BenchCfg
}

// GetObjectKind returns a schema object.
func (ForwardRes) GetObjectKind() schema.ObjectKind {
	return nil
}

// DeepCopyObject returns a container copy.
func (f ForwardRes) DeepCopyObject() runtime.Object {
	return f
}
