/*
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 cmd

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/apache/camel-k/pkg/util"

	"github.com/spf13/cobra"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/apache/camel-k/pkg/client"
	"github.com/apache/camel-k/pkg/client/camel/clientset/versioned"
	"github.com/apache/camel-k/pkg/util/kubernetes"
	"github.com/apache/camel-k/pkg/util/tar"
)

func newCmdDump(rootCmdOptions *RootCmdOptions) (*cobra.Command, *dumpCmdOptions) {
	options := dumpCmdOptions{
		RootCmdOptions: rootCmdOptions,
	}
	cmd := cobra.Command{
		Use:     "dump [filename]",
		Short:   "Dump the state of namespace",
		Long:    `Dump the state of currently used namespace. If no filename will be specified, the output will be on stdout`,
		PreRunE: decode(&options),
		RunE:    options.dump,
	}

	cmd.Flags().Int("logLines", 100, "Number of log lines to dump")
	cmd.Flags().Bool("compressed", false, "If the log file must be compressed in a tar.")
	return &cmd, &options
}

type dumpCmdOptions struct {
	*RootCmdOptions
	LogLines   int  `mapstructure:"logLines"`
	Compressed bool `mapstructure:"compressed" yaml:",omitempty"`
}

func (o *dumpCmdOptions) dump(cmd *cobra.Command, args []string) (err error) {
	c, err := o.GetCmdClient()
	if err != nil {
		return
	}

	if len(args) == 1 {
		err = util.WithFile(args[0], os.O_RDWR|os.O_CREATE, 0o644, func(file *os.File) error {
			if !o.Compressed {
				return dumpNamespace(o.Context, c, o.Namespace, file, o.LogLines)
			}
			err = dumpNamespace(o.Context, c, o.Namespace, file, o.LogLines)
			if err != nil {
				return err
			}
			tar.CreateTarFile([]string{file.Name()}, "dump."+file.Name()+"."+time.Now().Format(time.RFC3339)+".tar.gz", cmd)
			return nil
		})
	} else {
		return dumpNamespace(o.Context, c, o.Namespace, cmd.OutOrStdout(), o.LogLines)
	}
	return nil
}

func dumpNamespace(ctx context.Context, c client.Client, ns string, out io.Writer, logLines int) error {
	camelClient, err := versioned.NewForConfig(c.GetConfig())
	if err != nil {
		return err
	}
	pls, err := camelClient.CamelV1().IntegrationPlatforms(ns).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "Found %d platforms:\n", len(pls.Items))
	for _, p := range pls.Items {
		ref := p
		pdata, err := kubernetes.ToYAML(&ref)
		if err != nil {
			return err
		}
		fmt.Fprintf(out, "---\n%s\n---\n", string(pdata))
	}

	its, err := camelClient.CamelV1().Integrations(ns).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "Found %d integrations:\n", len(its.Items))
	for _, integration := range its.Items {
		ref := integration
		pdata, err := kubernetes.ToYAML(&ref)
		if err != nil {
			return err
		}
		fmt.Fprintf(out, "---\n%s\n---\n", string(pdata))
	}

	iks, err := camelClient.CamelV1().IntegrationKits(ns).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "Found %d integration kits:\n", len(iks.Items))
	for _, ik := range iks.Items {
		ref := ik
		pdata, err := kubernetes.ToYAML(&ref)
		if err != nil {
			return err
		}
		fmt.Fprintf(out, "---\n%s\n---\n", string(pdata))
	}

	cms, err := c.CoreV1().ConfigMaps(ns).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "Found %d ConfigMaps:\n", len(cms.Items))
	for _, cm := range cms.Items {
		ref := cm
		pdata, err := kubernetes.ToYAML(&ref)
		if err != nil {
			return err
		}
		fmt.Fprintf(out, "---\n%s\n---\n", string(pdata))
	}

	deployments, err := c.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}
	fmt.Fprintf(out, "Found %d deployments:\n", len(deployments.Items))
	for _, deployment := range deployments.Items {
		ref := deployment
		data, err := kubernetes.ToYAML(&ref)
		if err != nil {
			return err
		}
		fmt.Fprintf(out, "---\n%s\n---\n", string(data))
	}

	lst, err := c.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{})
	if err != nil {
		return err
	}

	fmt.Fprintf(out, "\nFound %d pods:\n", len(lst.Items))
	for _, pod := range lst.Items {
		fmt.Fprintf(out, "name=%s\n", pod.Name)
		dumpConditions("  ", pod.Status.Conditions, out)
		fmt.Fprintf(out, "  logs:\n")
		var allContainers []v1.Container
		allContainers = append(allContainers, pod.Spec.InitContainers...)
		allContainers = append(allContainers, pod.Spec.Containers...)
		for _, container := range allContainers {
			pad := "    "
			fmt.Fprintf(out, "%s%s\n", pad, container.Name)
			err := dumpLogs(ctx, c, fmt.Sprintf("%s> ", pad), ns, pod.Name, container.Name, out, logLines)
			if err != nil {
				fmt.Fprintf(out, "%sERROR while reading the logs: %v\n", pad, err)
			}
		}
	}
	return nil
}

func dumpConditions(prefix string, conditions []v1.PodCondition, out io.Writer) {
	for _, cond := range conditions {
		fmt.Fprintf(out, "%scondition type=%s, status=%s, reason=%s, message=%q\n", prefix, cond.Type, cond.Status, cond.Reason, cond.Message)
	}
}

func dumpLogs(ctx context.Context, c client.Client, prefix string, ns string, name string, container string, out io.Writer, logLines int) error {
	lines := int64(logLines)
	stream, err := c.CoreV1().Pods(ns).GetLogs(name, &v1.PodLogOptions{
		Container: container,
		TailLines: &lines,
	}).Stream(ctx)
	if err != nil {
		return err
	}

	scanner := bufio.NewScanner(stream)
	printed := false
	for scanner.Scan() {
		printed = true
		fmt.Fprintf(out, "%s%s\n", prefix, scanner.Text())
	}
	if !printed {
		fmt.Fprintf(out, "%s[no logs available]\n", prefix)
	}
	return stream.Close()
}
