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

import (
	"fmt"
	camelapiv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
	"io/ioutil"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/util/yaml"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

func main() {
	if len(os.Args) != 3 {
		println("usage: generator kamelets-path doc-root")
		os.Exit(1)
	}

	projectBaseDir := os.Args[1]
	docBaseDir := os.Args[2]

	kamelets := listKamelets(projectBaseDir)

	links := make([]string, 0)
	for _, k := range kamelets {
		links = updateImageLink(k, links)
	}

	saveNav(links, docBaseDir)
}

func updateImageLink(k camelapiv1.Kamelet, links []string) []string {
	return append(links, fmt.Sprintf("* xref:%s.adoc[]", k.Name))
}

func saveNav(links []string, out string) {
	content := "// THIS FILE IS AUTOMATICALLY GENERATED: DO NOT EDIT\n"
	for _, l := range links {
		content += l + "\n"
	}
	content += "// THIS FILE IS AUTOMATICALLY GENERATED: DO NOT EDIT\n"
	dest := filepath.Join(out, "nav.adoc")
	if _, err := os.Stat(dest); err == nil {
		err = os.Remove(dest)
		handleGeneralError(fmt.Sprintf("cannot remove file %q", dest), err)
	}
	err := ioutil.WriteFile(dest, []byte(content), 0666)
	handleGeneralError(fmt.Sprintf("cannot write file %q", dest), err)
	fmt.Printf("%q written\n", dest)
}

func listKamelets(dir string) []camelapiv1.Kamelet {
	scheme := runtime.NewScheme()
	err := camelapiv1.AddToScheme(scheme)
	handleGeneralError("cannot to add camel APIs to scheme", err)

	codecs := serializer.NewCodecFactory(scheme)
	gv := camelapiv1.SchemeGroupVersion
	gvk := schema.GroupVersionKind{
		Group:   gv.Group,
		Version: gv.Version,
		Kind:    "Kamelet",
	}
	decoder := codecs.UniversalDecoder(gv)

	kamelets := make([]camelapiv1.Kamelet, 0)
	files, err := ioutil.ReadDir(dir)
	filesSorted := make([]string, 0)
	handleGeneralError(fmt.Sprintf("cannot list dir %q", dir), err)
	for _, fd := range files {
		if !fd.IsDir() && strings.HasSuffix(fd.Name(), ".kamelet.yaml") {
			fullName := filepath.Join(dir, fd.Name())
			filesSorted = append(filesSorted, fullName)
		}
	}
	sort.Strings(filesSorted)
	for _, fileName := range filesSorted {
		content, err := ioutil.ReadFile(fileName)
		handleGeneralError(fmt.Sprintf("cannot read file %q", fileName), err)

		json, err := yaml.ToJSON(content)
		handleGeneralError(fmt.Sprintf("cannot convert file %q to JSON", fileName), err)

		kamelet := camelapiv1.Kamelet{}
		_, _, err = decoder.Decode(json, &gvk, &kamelet)
		handleGeneralError(fmt.Sprintf("cannot unmarshal file %q into Kamelet", fileName), err)
		kamelets = append(kamelets, kamelet)
	}
	return kamelets
}

func handleGeneralError(desc string, err error) {
	if err != nil {
		fmt.Printf("%s: %+v\n", desc, err)
		os.Exit(2)
	}
}
