// Copyright 2026 Google LLC
//
// Licensed 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 (
	"context"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"cloud.google.com/go/storage"
	"github.com/google/subcommands"

	"cos.googlesource.com/cos/tools.git/src/pkg/cos"
	"cos.googlesource.com/cos/tools.git/src/pkg/cosboot"
)

type showCmd struct{}

func (*showCmd) Name() string {
	return "show"
}

func (*showCmd) Synopsis() string {
	return "Show kernel arguments that will be used on the next boot."
}

func (*showCmd) Usage() string {
	return "show [disk image]\n"
}

func (*showCmd) SetFlags(f *flag.FlagSet) {}

func (*showCmd) showForGRUBBoot(disk string) subcommands.ExitStatus {
	cmdLine, err := cosboot.NextGRUBCmdLine(disk)
	if err != nil {
		fmt.Printf("Error reading next GRUB command line: %v\n", err)
		return subcommands.ExitFailure
	}
	cmdLine = strings.TrimSpace(strings.ReplaceAll(cmdLine, "$cmdline_extra", ""))
	cmdLine, err = appendEnabledArgs(disk, cmdLine)
	if err != nil {
		fmt.Printf("Error appending enabled arguments: %v\n", err)
		return subcommands.ExitFailure
	}
	fmt.Println(cmdLine)
	return subcommands.ExitSuccess
}

func downloadVmlinux(ctx context.Context, gcsClient *storage.Client, disk, outDir string) (string, error) {
	var envReader *cos.EnvReader
	if disk == "" {
		var err error
		envReader, err = cos.NewEnvReader("/")
		if err != nil {
			return "", err
		}
	} else {
		var err error
		envReader, err = cos.NewEnvReaderFromLocalDisk(disk)
		if err != nil {
			return "", err
		}
	}
	dl := cos.NewGCSDownloader(gcsClient, envReader, "", "", "", "", true)
	if err := dl.DownloadArtifact(ctx, outDir, "vmlinux"); err != nil {
		return "", err
	}
	return filepath.Join(outDir, "vmlinux"), nil
}

func (*showCmd) showForUKIBoot(ctx context.Context, disk, vmlinuxPath string) subcommands.ExitStatus {
	if vmlinuxPath == "" {
		gcsClient, err := storage.NewClient(ctx)
		if err != nil {
			fmt.Printf("Error creating GCS client: %v\n", err)
			return subcommands.ExitFailure
		}
		tmpDir, err := os.MkdirTemp("", "cos-kernel-args")
		if err != nil {
			fmt.Printf("Error creating tempdir: %v\n", err)
			return subcommands.ExitFailure
		}
		defer os.RemoveAll(tmpDir)
		vmlinuxPath, err = downloadVmlinux(ctx, gcsClient, disk, tmpDir)
		if err != nil {
			fmt.Printf("Could not download vmlinux and one was not provided: %v\n", err)
			return subcommands.ExitFailure
		}
	}
	cmdLine, err := cosboot.NextUKICmdLine(disk, vmlinuxPath)
	if err != nil {
		fmt.Printf("Error reading next UKI command line: %v\n", err)
		return subcommands.ExitFailure
	}
	fmt.Println(cmdLine)
	return subcommands.ExitSuccess
}

// Append enabled command line args to the list. This method assumes "$cmdline_extra" was
// removed from the cmdLine string
func appendEnabledArgs(disk string, cmdLine string) (string, error) {
	allowlist, _, err := readAllowlist(disk)
	if err != nil {
		// If allowlist is not found or cannot be read, we assume no extra args.
		// We don't want to fail `show` in this case
		return cmdLine, nil
	}

	bitfield, err := readBitfield(disk)
	if err != nil {
		// This is an actual error. If the bitfield simply doesn't exit, err will be nil.
		return "", fmt.Errorf("error reading bitfield: %v", err)
	}

	var enabledArgs []string
	for i, arg := range allowlist {
		if (bitfield & (1 << i)) != 0 {
			enabledArgs = append(enabledArgs, arg)
		}
	}

	if len(enabledArgs) > 0 {
		cmdLine += " " + strings.Join(enabledArgs, " ")
	}

	// return strings.TrimSpace(cmdLine), nil
	return cmdLine, nil
}

func (c *showCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
	disk := ""
	if f.NArg() > 0 {
		disk = f.Arg(0)
	}

	bootPath, err := cosboot.DiskBootPath(disk)
	if err != nil {
		fmt.Printf("Error identifying boot path: %v\n", err)
		return subcommands.ExitFailure
	}

	if bootPath == cosboot.GRUBBoot {
		return c.showForGRUBBoot(disk)
	} else if bootPath == cosboot.UKI {
		return c.showForUKIBoot(context.Background(), disk, *vmlinuxPath)
	} else {
		// This should never happen
		fmt.Println("Could not identify boot path")
		return subcommands.ExitFailure
	}
}
