// Copyright 2022 AppsFlyer
//
// 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 app

import (
	"github.com/AppsFlyer/terra-crust/cmd/types"
	"github.com/spf13/cobra"

	template_reader "github.com/AppsFlyer/terra-crust/internal/services/drivers/template_reader"
	version_control "github.com/AppsFlyer/terra-crust/internal/services/drivers/version_control"
)

func generateAllFiles(root *RootCommand) *cobra.Command {
	flags := types.TFGenerateFlags{}
	cmd := &cobra.Command{
		Use:     "terraform-all",
		Short:   "generate terraform locals , main and variables",
		Example: "",
		RunE: func(cmd *cobra.Command, args []string) error {
			log := root.log
			templateReader := template_reader.InitTemplateRemoteModule(log)
			gitDriver := version_control.InitGitProvider(log)

			if (flags.FetchRemote || flags.ExternalGit) && flags.MainTemplateFilePath != "" {
				remoteModulesMap, err := templateReader.GetRemoteModulesFromTemplate(flags.MainTemplateFilePath)
				if err != nil {
					log.Error("Failed parsing remote modules from custom template", err.Error())

					return err
				}

				if err = gitDriver.CloneModules(remoteModulesMap, flags.SourcePath, flags.ExternalGit); err != nil {
					log.Error("Failed cloning remote modules ", err.Error())

					return err
				}
				defer func() {
					if err = gitDriver. // The `CleanModulesFolders` function is used to clean up the folders of remote
						// modules that were cloned during the execution of the program. It takes the
						// `remoteModulesMap` and `flags.SourcePath` as parameters. It is called as a
						// deferred function at the end of the `generateAllFiles` command.
						CleanModulesFolders(remoteModulesMap, flags.SourcePath); err != nil {
						log.Errorf("Failed to clean up some of the remote resources please make sure to clean it manually and check the error , %s", err.Error())
					}
				}()
			}

			terraformSvc := InitTerraformGeneratorService(log)

			if err := terraformSvc.GenerateMain(flags.SourcePath, flags.DestinationPath, flags.MainTemplateFilePath); err != nil {
				log.Error("Failed generating the terraform main file", err.Error())

				return err
			}

			if err := terraformSvc.GenerateModuleDefaultLocals(flags.SourcePath, flags.DestinationPath); err != nil {
				log.Error("Failed generating the terraform locals file", err.Error())

				return err
			}

			if err := terraformSvc.GenerateModuleVariableObject(flags.SourcePath, flags.DestinationPath); err != nil {
				log.Error("Failed generating the terraform variable file", err.Error())

				return err
			}

			return nil
		},
	}

	cmd.Flags().StringVar(&flags.SourcePath, "source-path", "", "Required: General module folder path that contains all the sub modules flattened")
	cmd.Flags().StringVar(&flags.DestinationPath, "destination-path", "", "Required: Destination path to write the new terraform file")
	cmd.Flags().StringVar(&flags.MainTemplateFilePath, "main-template-path", "", "Optional: Custom main template path for generated module, will take default if not provided")
	cmd.Flags().BoolVar(&flags.FetchRemote, "fetch-remote", false, "Optional: Enable fetching of remote modules and exporting their variables in root module")
	cmd.Flags().BoolVar(&flags.ExternalGit, "ext-git", false, "Optional: Enable external git for remote modules")
	if err := cmd.MarkFlagRequired("source-path"); err != nil {
		root.log.Error("failed to set required flag on source-path", err.Error())
	}
	if err := cmd.MarkFlagRequired("destination-path"); err != nil {
		root.log.Error("failed to set required flag on destination-path", err.Error())
	}

	return cmd
}
