// SPDX-FileCopyrightText: 2021 Luke Granger-Brown <depot@lukegb.com>
//
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
	"fmt"
	"io"
	"io/fs"
	"log"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"
	"git.lukegb.com/lukegb/depot/web/fup/fupstatic"
)

func init() {
	rootCmd.AddCommand(extractstaticCmd)

	extractstaticCmd.Flags().BoolVarP(&extractstaticForceOverwrite, "force", "f", false, "If set, will overwrite existing files.")
}

var (
	extractstaticForceOverwrite bool

	extractstaticCmd = &cobra.Command{
		Use:     "extractstatic dir",
		Example: "extractstatic /srv/http/static",
		Short:   "Extracts static assets into a target directory.",
		Args:    cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			targetDir := args[0]
			log.Printf("extracting assets to %v", targetDir)
			return fs.WalkDir(fupstatic.Static, ".", func(fpath string, d fs.DirEntry, err error) error {
				if err != nil {
					return err
				}
				targetPath := filepath.Join(targetDir, fpath)
				fi, err := os.Stat(targetPath)
				if err != nil && !os.IsNotExist(err) {
					return fmt.Errorf("checking for existence of %q: %w", targetPath, err)
				}
				if d.IsDir() {
					switch {
					case fi != nil && !fi.IsDir():
						return fmt.Errorf("%q already exists and is not a directory", targetPath)
					case fi != nil:
						return nil
					default:
						// Ensure directory exists.
						return os.Mkdir(filepath.Join(targetDir, fpath), 0755)
					}
				}

				switch {
				case fi != nil && fi.IsDir():
					return fmt.Errorf("%q already exists and is a directory", targetPath)
				case fi != nil && !extractstaticForceOverwrite:
					return nil
				}

				src, err := fupstatic.Static.Open(fpath)
				if err != nil {
					return fmt.Errorf("open source %q: %w", fpath, err)
				}
				defer src.Close() // Don't care about errors for closing read-only file.

				dst, err := os.Create(targetPath)
				if err != nil {
					return fmt.Errorf("create target %q: %w", targetPath, err)
				}

				if _, err := io.Copy(dst, src); err != nil {
					return fmt.Errorf("copying from source %q to target %q: %w", fpath, targetPath, err)
				}

				if err := dst.Close(); err != nil {
					return fmt.Errorf("close target %q: %w", targetPath, err)
				}

				return nil
			})
		},
	}
)