// 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"
	"errors"
	"flag"
	"fmt"
	"os"

	"cloud.google.com/go/storage"
	"cos.googlesource.com/cos/tools.git/src/pkg/cosboot"
	"github.com/google/subcommands"
)

type sedCmd struct {
	command string
}

func (*sedCmd) Name() string {
	return "sed"
}

func (*sedCmd) Synopsis() string {
	return "Edit kernel arguments using a sed command."
}

func (*sedCmd) Usage() string {
	return "sed --command <sed-command> [disk image]\n"
}

func (c *sedCmd) SetFlags(f *flag.FlagSet) {
	f.StringVar(&c.command, "command", "", "The sed command to run")
}

func (c *sedCmd) validate() error {
	if c.command == "" {
		return errors.New("the --command flag is required.")
	}
	return nil
}

func (c *sedCmd) sedForGRUBBoot(disk, sedCmd string) subcommands.ExitStatus {
	if err := cosboot.EditGRUBConfig(disk, sedCmd); err != nil {
		fmt.Printf("Error editing grub configuration: %v\n", err)
		return subcommands.ExitFailure
	}
	return subcommands.ExitSuccess
}

func (c *sedCmd) sedForUKIBoot(ctx context.Context, disk, vmlinuxPath, sedCmd 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
		}
	}
	if err := cosboot.EditUKICmdLine(disk, vmlinuxPath, sedCmd); err != nil {
		fmt.Printf("Error editing UKI kernel command line: %v\n", err)
		return subcommands.ExitFailure
	}
	return subcommands.ExitSuccess
}

func (c *sedCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
	if err := c.validate(); err != nil {
		fmt.Printf("flag validation failure: %v\n", err)
		return subcommands.ExitUsageError
	}

	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.sedForGRUBBoot(disk, c.command)
	} else if bootPath == cosboot.UKI {
		return c.sedForUKIBoot(context.Background(), disk, *vmlinuxPath, c.command)
	} else {
		// This should never happen
		fmt.Println("Could not identify boot path")
		return subcommands.ExitFailure
	}
	return subcommands.ExitSuccess
}
