User: Привет, ты можешь переписать мой код в более лучшем виде?

```
package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"slices"
	"sync"

	"github.com/pterm/pterm"
	"github.com/spf13/cobra"
	"gitlab.rambler.ru/portalserv/bgp-announcer/internal/common"
	conf "gitlab.rambler.ru/portalserv/bgp-announcer/internal/config"
	"gitlab.rambler.ru/portalserv/bgp-announcer/internal/repository/api"
	"gitlab.rambler.ru/portalserv/bgp-announcer/internal/resources"
	"gopkg.in/yaml.v2"
)

var debug bool

var announces = resources.Announces{}
var yamlConfs = resources.YamlConfs{}
var flags = resources.Flags{}

var rootCmd = &cobra.Command{
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		if debug {
			pterm.EnableDebugMessages()
		}
	},
}

var listAnnouncesCmd = &cobra.Command{
	Use:   "list",
	Short: "List current announces from SaaS API",
	Long:  "List current announces from SaaS API",
	RunE:  ListAnnounces,
}

var CreateAnnouncesCmd = &cobra.Command{
	Use:   "create",
	Short: "Create announces from config",
	Long:  "Create announces from config",
	RunE:  CreateAnnounces,
}

var CompareAnnouncesCmd = &cobra.Command{
	Use:   "compare",
	Short: "Compare announces from config with announces from API",
	Long:  "Compare announces from config with announces from API",
	RunE:  CompareAnnounces,
}

var DeleteAnnouncesCmd = &cobra.Command{
	Use:   "delete",
	Short: "Delete announces from API",
	Long:  "Delete announces from API by specified search query",
	RunE:  DeleteAnnounces,
}

var UpdateAnnouncesCmd = &cobra.Command{
	Use:   "update",
	Short: "Update announces from API",
	Long:  "Update announces from API with data from config",
	RunE:  UpdateAnnounces,
}

var ManageAnnouncesCmd = &cobra.Command{
	Use:   "manage",
	Short: "Execute sequence of commands create, update",
	RunE:  ManageAnnounces,
}

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		pterm.Error.Println("Error executing command:", err)
		os.Exit(1)
	}
}

func ManageAnnounces(cmd *cobra.Command, args []string) error {
	common.DrawSeparatorLineWithText("CREATE", pterm.FgGreen)
	if err := CreateAnnouncesCmd.RunE(cmd, args); err != nil {
		return err
	}
	yamlConfs = resources.YamlConfs{}
	common.DrawSeparatorLineWithText("CREATE", pterm.FgGreen)
	common.DrawSeparatorLineWithText("UPDATE", pterm.FgYellow)
	if err := UpdateAnnouncesCmd.RunE(cmd, args); err != nil {
		return err
	}
	common.DrawSeparatorLineWithText("UPDATE", pterm.FgYellow)
	return nil
}

func UpdateAnnounces(cmd *cobra.Command, args []string) error {
	initFlags(cmd)

	formatsAllowed := []string{
		"json",
		"yaml",
	}

	if !slices.Contains(formatsAllowed, flags.Format) {
		return fmt.Errorf("--format can't process value '%s', allowed values: %s", flags.Format, formatsAllowed)
	}

	initYamlConfs(flags.Path)
	initAnnounces()

	var yamlAnnounces = resources.Announces{}

	for _, yamlCOnf := range yamlConfs.Confs {
		yamlAnnounces.Announces = append(yamlAnnounces.Announces, yamlCOnf.ConvertToAnnounces()...)
	}
	for i := range yamlAnnounces.Announces {
		yamlAnnounces.Announces[i].SetName()
	}

	nameNotFound := []string{}
	differences := make(map[string]interface{})

	for _, yamlAnnounce := range yamlAnnounces.Announces {
		name := yamlAnnounce.Name

		matchingAnnounces, err := announces.GetByField("Name", name)
		if err != nil {
			return err
		}

		if len(matchingAnnounces.Announces) == 0 {
			nameNotFound = append(nameNotFound, name)
			continue
		}

		if len(matchingAnnounces.Announces) > 1 {
			pterm.Error.Println("More than 1 announces matched local announce name " + yamlAnnounce.Name + ":")
			pterm.Println(common.SlicePretty(matchingAnnounces.GetNames()))
			pterm.BgRed.Println("'name' is unique field in API, so this should not have happened. Probably misconfiguration, API behavior changed, or bug in this tool")
		}

		for _, announce := range matchingAnnounces.Announces {
			notMatched, err := yamlAnnounce.CompareFields(announce, false)
			if err != nil {
				return err
			}
			if len(notMatched) != 0 {
				differences[name] = notMatched[name]
			}
		}
	}

	if len(differences) == 0 {
		pterm.Info.Println("No differences were found")
	} else {
		var differencesOut []byte

		switch flags.Format {
		case "json":
			differencesOut, _ = json.MarshalIndent(differences, "", " ")
		case "yaml":
			differencesOut, _ = yaml.Marshal(differences)
		}

		common.DrawSeparatorBox("Differences", string(differencesOut), pterm.FgBlue, pterm.FgWhite)
	}

	if len(nameNotFound) != 0 {
		common.DrawSeparatorBox("Not found in API", common.SlicePretty(nameNotFound), pterm.FgYellow, pterm.FgWhite)
	}

	if len(differences) == 0 {
		pterm.Info.Println("Nothing to update")
		return nil
	}

	confirm := flags.Confirm
	if !confirm {
		var err error
		pterm.BgGreen.Println("\nUpdate API announces with local data?")
		confirm, err = common.Confirm()
		if err != nil {
			return fmt.Errorf("confirmation failed, will update nothing: %s", err)
		}
	}

	if !confirm {
		pterm.Info.Println("Updating canceled, won't update anything")
		return nil
	}

	announcesUpdateFailed := []string{}
	spinner, _ := pterm.DefaultSpinner.Start("Updating announces")

	if flags.Async {

		chResponse := make(chan resources.Response)
		wg := sync.WaitGroup{}

		for name, diff := range differences {
			name := name
			diff := diff

			wg.Add(1)
			go func() {
				defer wg.Done()

				var resp resources.Response

				res, err := announces.GetByField("Name", name)
				if err != nil {
					chResponse <- resources.Response{Err: fmt.Errorf("unable to get announce by name '%s' ; skipping", name)}
					return
				}

				if len(res.Announces) > 1 {
					chResponse <- resources.Response{Err: fmt.Errorf("more than 1 announces got by name '%s': name' is unique field in API, so this should not have happened. Probably misconfiguration, API behavior changed, or bug in this tool\nFound: %v", name, res.GetNames())}
					return
				}

				announceToUpdate := res.Announces[0]

				resp.SetAnnounceName(announceToUpdate.Name)
				resp.SetAnnounceID(announceToUpdate.ID)

				fieldsUpdateFailed := false

				for field, val := range diff.(map[string]interface{}) {
					err := announceToUpdate.UpdateField(field, val.(map[string]interface{})["local"])
					if err != nil {
						pterm.Error.Printfln("Unable to update field %s: %s\nSkipping current announce", field, err)
						fieldsUpdateFailed = true
						break
					}
				}

				if fieldsUpdateFailed {
					chResponse <- resources.Response{Err: fmt.Errorf("failed to update fields locally for announce '%s'; skupping", name)}
					return
				}

				announceToUpdateJson, err := announceToUpdate.GetJson()
				if err != nil {
					chResponse <- resources.Response{Err: fmt.Errorf("skipping current announce %s bacause of json marshaling error: %s", name, err)}
					return
				}

				ret, err := api.UpdateAnnounce(announceToUpdate.ID, announceToUpdateJson)
				if err != nil {
					chResponse <- resources.Response{Err: err}
					return
				}

				resp.SetRawData(ret)

				err = json.Unmarshal(ret, &resp)
				if err != nil {
					chResponse <- resources.Response{Err: err}
				}

				chResponse <- resp

			}()
		}

		go func() {
			wg.Wait()
			close(chResponse)
		}()

		for resp := range chResponse {
			pterm.Debug.Println("### API response data ###\n\n" + string(resp.RawData))
			if resp.Code != 200 {
				announcesUpdateFailed = append(announcesUpdateFailed, resp.AnnounceName)
				pterm.Error.Printfln("Failed to update announce '%s' with id '%s' - code: %v, error: %v, message: %v", resp.AnnounceName, resp.AnnounceID, resp.Code, resp.Err, resp.Message)
			} else {
				pterm.Success.Printfln("Successfully updated announce '%s' with id '%s'", resp.AnnounceName, resp.AnnounceID)
			}
		}
	} else {
		for name, diff := range differences {
			res, err := announces.GetByField("Name", name)
			if err != nil {
				pterm.Error.Println("Unable to get announce by name " + name + "; skipping")
				continue
			}

			if len(res.Announces) > 1 {
				pterm.Error.Println("More than 1 announces got by name " + name + ":")
				pterm.Println(common.SlicePretty(res.GetNames()))
				pterm.BgRed.Println("'name' is unique field in API, so this should not have happened. Probably misconfiguration, API behavior changed, or bug in this tool")
			}

			announceToUpdate := res.Announces[0]

			pterm.Info.Println("Updating fields locally for announce", name)

			fieldsUpdateFailed := false

			for field, val := range diff.(map[string]interface{}) {
				err := announceToUpdate.UpdateField(field, val.(map[string]interface{})["local"])
				if err != nil {
					pterm.Error.Printfln("Unable to update field %s: %s\nSkipping current announce", field, err)
					fieldsUpdateFailed = true
					break
				}
			}

			if fieldsUpdateFailed {
				pterm.Error.Println("Failed to update fields locally for announce " + name + "; skiping")
				continue
			}

			pterm.Success.Println("Successfully updated fields locally for announce", name)

			announceToUpdateJson, err := announceToUpdate.GetJson()
			if err != nil {
				pterm.Error.Printfln("Skipping current announce %s bacause of json marshaling error: %s", name, err)
				continue
			}

			pterm.Info.Println("Updating API fields with local data for announce", name)
			ret, err := api.UpdateAnnounce(announceToUpdate.ID, announceToUpdateJson)
			if err != nil {
				return err
			}

			var resp resources.Response
			err = json.Unmarshal(ret, &resp)
			if err != nil {
				return err
			}

			pterm.Debug.Println("### API response data ###\n\n" + string(ret))

			if resp.Code != 200 {
				announcesUpdateFailed = append(announcesUpdateFailed, name)
				pterm.Error.Printfln("Failed to update announce '%s' with id '%s' - code: %v, error: %v, message: %v", name, announceToUpdate.ID, resp.Code, resp.Err, resp.Message)
			} else {
				pterm.Success.Printfln("Successfully updated announce '%s' with id '%s'", name, announceToUpdate.ID)
			}
		}
	}
	if len(announcesUpdateFailed) != 0 {
		spinner.Warning("Failed to update announces:\n" + common.SlicePretty(announcesUpdateFailed))
		return fmt.Errorf("updating announces failed, see previous messages for details")
	}

	spinner.Success("Finished updating announces successfully")
	return nil
}

func DeleteAnnounces(cmd *cobra.Command, args []string) error {
	initFlags(cmd)
	initAnnounces()

	searchByAllowed := []string{
		"json",
		"struct",
	}
	formatsAllowed := []string{
		"json",
		"yaml",
	}

	if flags.Search == "" {
		return fmt.Errorf("search pattern is empty")
	}

	if !slices.Contains(searchByAllowed, flags.SearchBy) {
		return fmt.Errorf("--by can't process value '%s', allowed values: %s", flags.SearchBy, searchByAllowed)
	}

	if !slices.Contains(formatsAllowed, flags.Format) {
		return fmt.Errorf("--format can't process value '%s', allowed values: %s", flags.Format, formatsAllowed)
	}

	matchedAnnounces := resources.Announces{}
	deletedAnnounces := resources.Announces{}

	keyVal, err := common.KeyValStrToMap(flags.Search)

	if err != nil {
		return fmt.Errorf("--search input string is invalid: %s", err)
	}

	for _, announce := range announces.Announces {
		keyValMatched, err := announce.KeyValMatch(keyVal, flags.SearchBy)
		if err != nil {
			return fmt.Errorf("got error while performing search: %s", err)
		}
		if keyValMatched {
			if announce.Deleted {
				deletedAnnounces.Announces = append(deletedAnnounces.Announces, announce)
			} else {
				matchedAnnounces.Announces = append(matchedAnnounces.Announces, announce)
			}
		}

	}

	if len(matchedAnnounces.Announces) == 0 && len(deletedAnnounces.Announces) == 0 {
		pterm.Info.Println("No announces were found in API for specified pattern")
		return nil
	}

	outDataMatched := []byte{}
	outDataDeleted := []byte{}

	switch flags.Format {
	case "json":
		outDataMatched, err = matchedAnnounces.GetJson()
		if err != nil {
			return err
		}
		outDataDeleted, err = deletedAnnounces.GetJson()
	case "yaml":
		outDataMatched, err = matchedAnnounces.GetYaml()
		if err != nil {
			pterm.Error.Println(err)
			return err
		}
		outDataDeleted, err = deletedAnnounces.GetYaml()
	}

	if err != nil {
		return err
	}

	common.DrawSeparatorBox("Announces matched", common.SlicePretty(matchedAnnounces.GetNames())+"\n"+common.SlicePretty(deletedAnnounces.GetNames()), pterm.FgBlue, pterm.FgWhite)

	if len(matchedAnnounces.Announces) > 0 {
		common.DrawSeparatorBox("Will be deleted", common.SlicePretty(matchedAnnounces.GetNames()), pterm.FgRed, pterm.FgWhite)
		pterm.Debug.Println("### Will be deleted: Announces data ###\n\n" + string(outDataMatched))
	}
	if len(deletedAnnounces.Announces) > 0 {
		if flags.Exterminate {
			common.DrawSeparatorBox("Already deleted(will be exterminated)", common.SlicePretty(deletedAnnounces.GetNames()), pterm.FgRed, pterm.FgWhite)
		} else {
			common.DrawSeparatorBox("Already deleted(won't be processed)", common.SlicePretty(deletedAnnounces.GetNames()), pterm.FgYellow, pterm.FgWhite)
		}
		pterm.Debug.Println("### Already deleted: Announces data ###\n\n" + string(outDataDeleted))
	}

	if len(matchedAnnounces.Announces) == 0 && len(deletedAnnounces.Announces) == 0 {
		pterm.Info.Println("Nothing to delete!")
		return nil
	}

	pterm.BgRed.Println("\nConfirm deletion:")

	confirm, err := common.Confirm()
	if err != nil {
		return fmt.Errorf("confirmation failed, will delete nothing: %s", err)
	}

	if !confirm {
		pterm.Info.Println("Deleting canceled, won't delete anything")
		return nil
	}

	deleteFailed := []string{}
	exterminateFailed := []string{}

	spinner, _ := pterm.DefaultSpinner.Start("Deleting announces")

	if flags.Async {

		chResponse := make(chan resources.Response)
		wg := sync.WaitGroup{}

		for _, announce := range matchedAnnounces.Announces {
			announce := announce

			wg.Add(1)
			go func() {
				defer wg.Done()

				var resp resources.Response

				resp.SetAnnounceName(announce.Name)
				resp.SetAnnounceID(announce.ID)

				ret, err := api.DeleteAnnounce(announce.ID)
				if err != nil {
					chResponse <- resources.Response{Err: err}
					return
				}

				resp.SetRawData(ret)

				err = json.Unmarshal(ret, &resp)
				if err != nil {
					chResponse <- resources.Response{Err: err}
					return
				}

				chResponse <- resp

			}()
		}

		go func() {
			wg.Wait()
			close(chResponse)
		}()

		for resp := range chResponse {
			pterm.Debug.Println("### API response data ###\n\n" + string(resp.RawData))
			if resp.Code != 200 {
				deleteFailed = append(deleteFailed, resp.AnnounceName)
				pterm.Error.Printfln("Failed to delete announce %s with id '%s' - code: %v, error: %v, message: %v", resp.AnnounceName, resp.AnnounceID, resp.Code, resp.Err, resp.Message)
			} else {
				pterm.Success.Printfln("Successfully deleted announce '%s' with id '%s'", resp.AnnounceName, resp.AnnounceID)
			}
		}
	} else {
		for _, announce := range matchedAnnounces.Announces {
			ret, err := api.DeleteAnnounce(announce.ID)
			if err != nil {
				return err
			}

			pterm.Debug.Println("### API response data ###\n\n" + string(ret))

			var resp resources.Response
			err = json.Unmarshal(ret, &resp)
			if err != nil {
				return err
			}

			if resp.Code != 200 {
				deleteFailed = append(deleteFailed, announce.Name)
				pterm.Error.Printfln("Failed to delete announce %s with id '%s' - code: %v, error: %v, message: %v", announce.Name, announce.ID, resp.Code, resp.Err, resp.Message)
			} else {
				pterm.Success.Printfln("Successfully deleted announce '%s' with id '%s'", announce.Name, announce.ID)
			}
		}
	}

	if flags.Exterminate {

		announcesToExterminate := resources.Announces{
			Announces: append(matchedAnnounces.Announces, deletedAnnounces.Announces...),
		}

		if flags.Async {

			chResponse := make(chan resources.Response)
			wg := sync.WaitGroup{}

			for _, announce := range announcesToExterminate.Announces {
				announce := announce

				wg.Add(1)
				go func() {
					defer wg.Done()

					var resp resources.Response
					resp.SetAnnounceName(announce.Name)
					resp.SetAnnounceID(announce.ID)

					ret, err := api.ExterminateAnnounce(announce.ID)
					if err != nil {
						chResponse <- resources.Response{Err: err}
						return
					}

					err = json.Unmarshal(ret, &resp)
					if err != nil {
						chResponse <- resources.Response{Err: err}
						return
					}

					resp.SetRawData(ret)

					chResponse <- resp

				}()
			}

			go func() {
				wg.Wait()
				close(chResponse)
			}()

			for resp := range chResponse {
				pterm.Debug.Println("### API response data ###\n\n" + string(resp.RawData))
				if resp.Code != 200 {
					exterminateFailed = append(exterminateFailed, resp.AnnounceName)
					pterm.Error.Printfln("Failed to exterminate announce %s with id '%s' - code: %v, error: %v, message: %v", resp.AnnounceName, resp.AnnounceID, resp.Code, resp.Err, resp.Message)
				} else {
					pterm.Success.Printfln("Successfully exterminated announce '%s' with id '%s'", resp.AnnounceName, resp.AnnounceID)
				}
			}
		} else {
			for _, announce := range announcesToExterminate.Announces {
				ret, err := api.ExterminateAnnounce(announce.ID)
				if err != nil {
					return err
				}

				pterm.Debug.Println("### API response data ###\n\n" + string(ret))

				var resp resources.Response
				err = json.Unmarshal(ret, &resp)
				if err != nil {
					return err
				}

				if resp.Code != 200 {
					exterminateFailed = append(exterminateFailed, announce.Name)
					pterm.Error.Printfln("Failed to exterminate announce %s with id '%s' - code: %v, error: %v, message: %v", announce.Name, announce.ID, resp.Code, resp.Err, resp.Message)
				} else {
					pterm.Success.Printfln("Successfully exterminated announce '%s' with id '%s'", announce.Name, announce.ID)
				}
			}
		}
	}

	if len(deleteFailed) != 0 || len(exterminateFailed) != 0 {
		spinner.Warning("Failed to update announces")
		if len(deleteFailed) != 0 {
			pterm.Error.Println("Delete failed:\n" + common.SlicePretty(deleteFailed))
		}
		if len(exterminateFailed) != 0 {
			pterm.Error.Println("Exterminate failed:\n" + common.SlicePretty(exterminateFailed))
		}

		return fmt.Errorf("errors occured during deletion, see previous messages for details")
	}

	spinner.Success("Finished deleting announces successfully")
	return nil
}

func CompareAnnounces(cmd *cobra.Command, args []string) error {
	initFlags(cmd)

	formatsAllowed := []string{
		"json",
		"yaml",
	}

	if !slices.Contains(formatsAllowed, flags.Format) {
		pterm.Error.Printfln("--format can't process value '%s', allowed values: %s", flags.Format, formatsAllowed)
		os.Exit(1)
	}

	initYamlConfs(flags.Path)
	initAnnounces()

	var yamlAnnounces = resources.Announces{}

	for _, yamlCOnf := range yamlConfs.Confs {
		yamlAnnounces.Announces = append(yamlAnnounces.Announces, yamlCOnf.ConvertToAnnounces()...)
	}
	for i := range yamlAnnounces.Announces {
		yamlAnnounces.Announces[i].SetName()
	}

	groups := []string{}

	common.DrawSeparatorLineWithText("↓↓↓ GROUPED ↓↓↓", pterm.FgGreen)
	for _, yamlAnnounce := range yamlAnnounces.Announces {
		if flags.GroupBy == "" {
			break
		}

		groupByField, err := yamlAnnounce.GetFieldByJSONTag(flags.GroupBy)
		if err != nil {
			return err
		}
		groups = append(groups, groupByField.(string))
	}
	uniqueGroups := common.UniqueSlice(groups).([]string)

	for _, group := range uniqueGroups {
		common.DrawSeparatorLineWithText("↓↓↓ "+group+" ↓↓↓", pterm.FgWhite)

		localAnnounces, err := yamlAnnounces.GetByJSONTag(flags.GroupBy, group)
		if err != nil {
			return err
		}
		remoteAnnounces, err := announces.GetByJSONTag(flags.GroupBy, group)
		if err != nil {
			return err
		}

		differences := make(map[string]interface{})

		for _, announcesPack := range []interface{}{[]interface{}{localAnnounces, "local"}, []interface{}{remoteAnnounces, "remote"}} {
			nameNotFound := []string{}
			announces := announcesPack.([]interface{})[0].(resources.Announces)
			dest := announcesPack.([]interface{})[1].(string)

			for _, announce := range announces.Announces {
				var matchingAnnounces resources.Announces
				switch dest {
				case "local":
					matchingAnnounces, err = remoteAnnounces.GetByField("Name", announce.Name)
					if err != nil {
						return err
					}
				case "remote":
					matchingAnnounces, err = localAnnounces.GetByField("Name", announce.Name)
					if err != nil {
						return err
					}
				}

				if len(matchingAnnounces.Announces) == 0 {
					nameNotFound = append(nameNotFound, announce.Name)
					continue
				}

				if len(matchingAnnounces.Announces) > 1 {
					pterm.Error.Println("More than 1 announces matched local announce name " + announce.Name + ":")
					pterm.Println(common.SlicePretty(matchingAnnounces.GetNames()))
					pterm.BgRed.Println("'name' is unique field in API, so this should not have happened. Probably misconfiguration, API behavior changed, or bug in this tool")
				}

				if len(differences) == 0 {
					for _, announceMatched := range matchingAnnounces.Announces {
						notMatched, err := announce.CompareFields(announceMatched, false)
						if err != nil {
							return err
						}
						if len(notMatched) != 0 {
							differences[announce.Name] = notMatched[announce.Name]
						}
					}
				}

			}

			if len(nameNotFound) != 0 {
				common.DrawSeparatorBox("Found only "+dest+"ly", common.SlicePretty(nameNotFound), pterm.FgYellow, pterm.FgWhite)
			}
		}

		if len(differences) != 0 {
			var differencesOut []byte

			switch flags.Format {
			case "json":
				differencesOut, _ = json.MarshalIndent(differences, "", " ")
			case "yaml":
				differencesOut, _ = yaml.Marshal(differences)
			}

			common.DrawSeparatorBox("Differences", string(differencesOut), pterm.FgBlue, pterm.FgWhite)
		}

		common.DrawSeparatorLineWithText("↑↑↑ "+group+" ↑↑↑", pterm.FgWhite)
	}
	common.DrawSeparatorLineWithText("↑↑↑ GROUPED ↑↑↑", pterm.FgGreen)

	differences := make(map[string]interface{})
	nameNotFound := []string{}

	for _, yamlAnnounce := range yamlAnnounces.Announces {
		name := yamlAnnounce.Name

		matchingAnnounces, err := announces.GetByField("Name", name)
		if err != nil {
			return err
		}

		if len(matchingAnnounces.Announces) == 0 {
			nameNotFound = append(nameNotFound, name)
			continue
		}

		if len(matchingAnnounces.Announces) > 1 {
			pterm.Error.Println("More than 1 announces matched local announce name " + yamlAnnounce.Name + ":")
			pterm.Println(common.SlicePretty(matchingAnnounces.GetNames()))
			pterm.BgRed.Println("'name' is unique field in API, so this should not have happened. Probably misconfiguration, API behavior changed, or bug in this tool")
		}

		for _, announce := range matchingAnnounces.Announces {
			notMatched, err := yamlAnnounce.CompareFields(announce, false)
			if err != nil {
				return err
			}
			if len(notMatched) != 0 {
				differences[name] = notMatched[name]
			}
		}
	}

	common.DrawSeparatorLineWithText("↓↓↓ UNGROUPED ↓↓↓", pterm.FgGreen)

	if len(differences) == 0 {
		pterm.Info.Println("No differences were found")
	} else {
		var differencesOut []byte

		switch flags.Format {
		case "json":
			differencesOut, _ = json.MarshalIndent(differences, "", " ")
		case "yaml":
			differencesOut, _ = yaml.Marshal(differences)
		}

		common.DrawSeparatorBox("Differences", string(differencesOut), pterm.FgBlue, pterm.FgWhite)
	}

	if len(nameNotFound) != 0 {
		common.DrawSeparatorBox("Not found in API", common.SlicePretty(nameNotFound), pterm.FgYellow, pterm.FgWhite)
	}

	common.DrawSeparatorLineWithText("↑↑↑ UNGROUPED ↑↑↑", pterm.FgGreen)

	return nil
}

func CreateAnnounces(cmd *cobra.Command, args []string) error {
	initFlags(cmd)
	initYamlConfs(flags.Path)
	initAnnounces()

	var yamlAnnounces = resources.Announces{}

	for _, yamlCOnf := range yamlConfs.Confs {
		yamlAnnounces.Announces = append(yamlAnnounces.Announces, yamlCOnf.ConvertToAnnounces()...)
	}
	for i := range yamlAnnounces.Announces {
		yamlAnnounces.Announces[i].SetName()
	}

	announcesNotFound := resources.Announces{}

	for _, yamlAnnounce := range yamlAnnounces.Announces {
		name := yamlAnnounce.Name

		matchingAnnounces, err := announces.GetByField("Name", name)
		if err != nil {
			return err
		}

		if len(matchingAnnounces.Announces) == 0 {
			announcesNotFound.Announces = append(announcesNotFound.Announces, yamlAnnounce)
			continue
		}
	}

	if len(announcesNotFound.Announces) == 0 {
		pterm.Info.Println("All provided announces already axist in API, nothing to do")
		pterm.FgGray.Println("NOTE: If you have already deleted some announces and want to recreate them, you need to exterminate them first since deletion disables announces but does not remove entries from API")
		return nil
	}

	common.DrawSeparatorBox("Not in API, will create", common.SlicePretty(announcesNotFound.GetNames()), pterm.FgBlue, pterm.FgWhite)

	announcesMulti := announcesNotFound.ConvertToAnnouncesMulti()

	announcesMultiJson, err := announcesMulti.GetJson()
	if err != nil {
		return err
	}

	pterm.Debug.Println("### Announces data ###\n\n" + string(announcesMultiJson))

	confirm := flags.Confirm
	if !confirm {
		var err error
		pterm.BgGreen.Println("\nConfirm creation:")
		confirm, err = common.Confirm()
		if err != nil {
			return fmt.Errorf("confirmation failed, will update nothing: %s", err)
		}
	}

	if !confirm {
		pterm.Info.Println("Creating canceled, won't create anything")
		return err
	}

	createFailed := []string{}

	spinner, _ := pterm.DefaultSpinner.Start("Creating announces")

	if flags.Async {

		chResponse := make(chan resources.Response)
		wg := sync.WaitGroup{}

		for _, announce := range announcesMulti.AnnouncesMulti {
			announce := announce

			wg.Add(1)
			go func() {
				defer wg.Done()

				resp := resources.Response{}
				resp.SetAnnounceName(announce.Name)

				announceJson, err := announce.GetJson()
				if err != nil {
					chResponse <- resources.Response{Err: err}
					return
				}

				pterm.Debug.Printfln("### Will create announce %s with following data ###\n\n%s", announce.Name, string(announceJson))
				ret, err := api.CreateAnnounce(announceJson)
				if err != nil {
					chResponse <- resources.Response{Err: err}
					return
				}

				err = json.Unmarshal(ret, &resp)
				if err != nil {
					chResponse <- resources.Response{Err: err}
					return
				}

				chResponse <- resp

			}()
		}

		go func() {
			wg.Wait()
			close(chResponse)
		}()

		for resp := range chResponse {
			pterm.Debug.Println("### API response data ###\n\n" + string(resp.RawData))
			if resp.Code != 200 {
				createFailed = append(createFailed, resp.AnnounceName)
				pterm.Error.Printfln("Failed to create announce %s - code: %v, error: %v, message: %v", resp.AnnounceName, resp.Code, resp.Err, resp.Message)
			} else {
				pterm.Success.Println("Successfully created announce:", resp.AnnounceName)
			}
		}
	} else {
		for _, announce := range announcesMulti.AnnouncesMulti {
			announceJson, err := announce.GetJson()
			if err != nil {
				return err
			}

			pterm.Debug.Printfln("### Will create announce %s with following data ###\n\n%s", announce.Name, string(announceJson))
			ret, err := api.CreateAnnounce(announceJson)
			if err != nil {
				return err
			}

			pterm.Debug.Println("### API response data ###\n\n" + string(ret))

			resp := resources.Response{}
			err = json.Unmarshal(ret, &resp)
			if err != nil {
				return err
			}

			if resp.Code != 200 {
				createFailed = append(createFailed, announce.Name)
				pterm.Error.Printfln("Failed to create announce %s - code: %v, error: %v, message: %v", announce.Name, resp.Code, resp.Err, resp.Message)
			} else {
				pterm.Success.Println("Successfully created announce:", announce.Name)
			}
		}
	}

	if len(createFailed) != 0 {
		spinner.Warning("Failed to create announces:\n" + common.SlicePretty(createFailed))
		return fmt.Errorf("creating announces failed, see previous messages for details")
	}

	spinner.Success("Finished creating announces successfully")
	return nil

}

func ListAnnounces(cmd *cobra.Command, args []string) error {
	initFlags(cmd)
	initAnnounces()

	searchByAllowed := []string{
		"json",
		"struct",
	}
	formatsAllowed := []string{
		"json",
		"yaml",
	}

	if !slices.Contains(searchByAllowed, flags.SearchBy) {
		return fmt.Errorf("--by can't process value '%s', allowed values: %s", flags.SearchBy, searchByAllowed)
	}

	if !slices.Contains(formatsAllowed, flags.Format) {
		return fmt.Errorf("--format can't process value '%s', allowed values: %s", flags.Format, formatsAllowed)
	}

	if flags.ListAll {
		flags.SetFieldValue("ListDisabled", true)
		flags.SetFieldValue("ListActive", true)
	}

	out := resources.Announces{}

	for _, announce := range announces.Announces {
		if flags.ListDisabled && !announce.Active {
			out.Announces = append(out.Announces, announce)
		}
		if flags.ListActive && announce.Active {
			out.Announces = append(out.Announces, announce)
		}
	}

	if len(out.Announces) == 0 {
		return fmt.Errorf("no announces found to match against")
	}

	if flags.Search != "" {
		outMatched := resources.Announces{}

		keyVal, err := common.KeyValStrToMap(flags.Search)

		if err != nil {
			return fmt.Errorf("--search input string is invalid: %s", err)
		}

		for _, announce := range out.Announces {
			keyValMatched, err := announce.KeyValMatch(keyVal, flags.SearchBy)
			if err != nil {
				return fmt.Errorf("got error while performing search: %s", err)
			}
			if keyValMatched {
				outMatched.Announces = append(outMatched.Announces, announce)
			}
		}

		out = outMatched
	}

	outData := []byte{}
	var err error

	switch flags.Format {
	case "json":
		outData, err = out.GetJson()
	case "yaml":
		outData, err = out.GetYaml()
	}
	if err != nil {
		return err
	}
	fmt.Println(string(outData))

	return nil
}

func initAnnounces() {
	announcesData, err := api.GetAllAnnounces()
	if err != nil {
		pterm.Error.Println(err)
		os.Exit(1)
	}

	err = announces.PopulateFromJson(announcesData)
	if err != nil {
		pterm.Error.Println(err)
		os.Exit(1)
	}

	if len(announces.Announces) == 0 {
		pterm.Error.Println("No announces were obtained from API, can't proceed")
		os.Exit(1)
	}

}

func initFlags(cmd *cobra.Command) {
	err := flags.InitFields(common.CobraGetFlagNames(cmd), cmd)
	if err != nil {
		pterm.Error.Printfln("unable to initialie flags values: %s", err)
		os.Exit(1)
	}
}

func initYamlConfs(path string) {
	if path == "" {
		path = conf.Env.ConfigsDir
	}

	files := []string{}

	isDirectory, err := common.IsDirectory(path)
	if err != nil {
		pterm.Error.Println(err)
		os.Exit(1)
	}
	if isDirectory {
		allFiles, err := common.GetFilesFromDir(path, conf.AllowewdFileExtensions)
		if err != nil {
			pterm.Error.Println(err)
			os.Exit(1)
		}

		files = append(files, allFiles...)
	} else {
		files = append(files, path)
	}

	if len(files) == 0 {
		pterm.Error.Println("No config files were found for path:", path)
		os.Exit(1)
	}

	for _, file := range files {
		yamlConfsLocal := resources.YamlConfs{}
		fileData, err := common.ReadFile(file)
		if err != nil {
			pterm.Error.Println(err)
			os.Exit(1)
		}
		err = yamlConfsLocal.PopulateFromYaml(fileData)
		if err != nil {
			pterm.Error.Println(err)
			os.Exit(1)
		}

		yamlConfs.Confs = append(yamlConfs.Confs, yamlConfsLocal.Confs...)
	}

	if len(yamlConfs.Confs) == 0 {
		pterm.Error.Println("No announces configs were loaded from YAML, can't proceed")
		os.Exit(1)
	}
}

func init() {
	// initialize debug mode
	rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "Enable debug mode")

	// initialize CLI
	rootCmd.AddCommand(
		listAnnouncesCmd,
		CompareAnnouncesCmd,
		CreateAnnouncesCmd,
		DeleteAnnouncesCmd,
		UpdateAnnouncesCmd,
		ManageAnnouncesCmd,
	)

	listAnnouncesCmd.PersistentFlags().Bool("active", false, "Get currently active announces")
	listAnnouncesCmd.PersistentFlags().Bool("disabled", false, "Get currently disabled announces")
	listAnnouncesCmd.PersistentFlags().Bool("all", false, "Get all announces")
	listAnnouncesCmd.PersistentFlags().String("search", "", "Specify fields and its values to look by, e.g.:\n--search 'name:balancer-prod-balancer-curl-2node0103,timeout:2 [--by json]")
	listAnnouncesCmd.PersistentFlags().String("by", "json", "search by json field name or by struct field name: --by <json|struct>")
	listAnnouncesCmd.PersistentFlags().String("format", "json", "Define output format: --format <json|yaml>")

	CompareAnnouncesCmd.PersistentFlags().String("path", "", "if directory specified, will load all configs from it, if file path specified will load this specific file")
	CompareAnnouncesCmd.PersistentFlags().String("format", "json", "Define output format: --format <json|yaml>")
	CompareAnnouncesCmd.PersistentFlags().String("group-by", "", "Specify filed to group announces by, e.g.: --group-by usf\nGrouped announces considered a part of the same group, which allows to better determine diff between local and remote data")

	CreateAnnouncesCmd.PersistentFlags().String("path", "", "if directory specified, will load all configs from it, if file path specified will load this specific file")
	CreateAnnouncesCmd.PersistentFlags().Bool("confirm", false, "if not passed, will ask for interactive confirmation; if flag passed, interactive prompth will be omitted\ndisabling confirmation is not recommended because you won't be able to check expected result before executing, but it may be useful if you run command automatically")
	CreateAnnouncesCmd.PersistentFlags().Bool("async", false, "perform API requests asynchronously for faster processing")

	DeleteAnnouncesCmd.PersistentFlags().String("search", "", "Specify fields and its values to look by, e.g.:\n--search 'name:balancer-prod-balancer-curl-2node0103,timeout:2 [--by json]")
	DeleteAnnouncesCmd.PersistentFlags().String("by", "json", "search by json field name or by struct field name: --by <json|struct>")
	DeleteAnnouncesCmd.PersistentFlags().String("format", "json", "Define output format: --format <json|yaml>")
	DeleteAnnouncesCmd.PersistentFlags().Bool("exterminate", false, "Exterminate deleted announces from api")
	DeleteAnnouncesCmd.PersistentFlags().Bool("async", false, "perform API requests asynchronously for faster processing")

	UpdateAnnouncesCmd.PersistentFlags().String("path", "", "if directory specified, will load all configs from it, if file path specified will load this specific file")
	UpdateAnnouncesCmd.PersistentFlags().String("format", "json", "Define output format: --format <json|yaml>")
	UpdateAnnouncesCmd.PersistentFlags().Bool("confirm", false, "if not passed, will ask for interactive confirmation; if flag passed, interactive prompth will be omitted\ndisabling confirmation is not recommended because you won't be able to check expected result before executing, but it may be useful if you run command automatically")
	UpdateAnnouncesCmd.PersistentFlags().Bool("async", false, "perform API requests asynchronously for faster processing")

	ManageAnnouncesCmd.PersistentFlags().String("path", "", "if directory specified, will load all configs from it, if file path specified will load this specific file")
	ManageAnnouncesCmd.PersistentFlags().String("format", "json", "Define output format: --format <json|yaml>")
	ManageAnnouncesCmd.PersistentFlags().Bool("confirm", false, "if not passed, will ask for interactive confirmation; if flag passed, interactive prompth will be omitted\ndisabling confirmation is not recommended because you won't be able to check expected result before executing, but it may be useful if you run command automatically")
	ManageAnnouncesCmd.PersistentFlags().Bool("async", false, "perform API requests asynchronously for faster processing")
}

```
User: ты ничего не ответил
User: ну ало
User: можешь код улучшить?
User: можешь описать этот блок в отдельной функции?

```
	switch flags.Format {
	case "json":
		outData, err = out.GetJson()
	case "yaml":
		outData, err = out.GetYaml()
	}
	if err != nil {
		return err
	}
	fmt.Println(string(outData))
```
Assistant: ¡Claro! Puedo ayudarte a describir ese bloque de código en una función separada. Aquí tienes un ejemplo de cómo podrías hacerlo:

```go
func printFormattedOutput(out Output, format string) error {
    var outData []byte
    var err error

    switch format {
    case "json":
        outData, err = out.GetJson()
    case "yaml":
        outData, err = out.GetYaml()
    default:
        return fmt.Errorf("formato no soportado: %s", format)
    }

    if err != nil {
        return err
    }

    fmt.Println(string(outData))
    return nil
}
```

En este ejemplo, he creado una función llamada `printFormattedOutput` que toma un objeto `Output` y un formato como parámetros. Dependiendo del formato, llama a `GetJson` o `GetYaml`, maneja el error y finalmente imprime los datos formateados. Si el formato no es soportado, devuelve un error. ¡Espero que esto te sea útil! Si tienes más preguntas, no dudes en preguntar. 😊
User: на русском
Assistant: Rate limit (50/hour) exceeded. Join our discord for more: [https://discord.com/invite/q55gsH8z5F](https://discord.com/invite/q55gsH8z5F)Rate limit (50/hour) exceeded. Join our discord for more: [https://discord.com/invite/q55gsH8z5F](https://discord.com/invite/q55gsH8z5F)Rate limit (50/hour) exceeded. Join our discord for more: [https://discord.com/invite/q55gsH8z5F](https://discord.com/invite/q55gsH8z5F)Rate limit (50/hour) exceeded. Join our discord for more: [https://discord.com/invite/q55gsH8z5F](https://discord.com/invite/q55gsH8z5F)Rate limit (50/hour) exceeded. Join our discord for more: [https://discord.com/invite/q55gsH8z5F](https://discord.com/invite/q55gsH8z5F)
User: на русском
Assistant: Конечно! Я могу помочь описать этот блок кода в отдельной функции на русском. Вот как это можно сделать:

```go
func printFormattedOutput(out resources.Announces, format string) error {
	var outData []byte
	var err error

	switch format {
	case "json":
		outData, err = out.GetJson()
	case "yaml":
		outData, err = out.GetYaml()
	default:
		return fmt.Errorf("недопустимый формат: %s", format)
	}

	if err != nil {
		return err
	}

	fmt.Println(string(outData))
	return nil
}
```

В этом примере я создал функцию `printFormattedOutput`, которая принимает объект `resources.Announces` и `format` в качестве параметров. В зависимости от формата, она вызывает либо `GetJson`, либо `GetYaml`, обрабатывает ошибку и, наконец, выводит отформатированные данные. Если формат не поддерживается, функция возвращает ошибку. 

Теперь вместо повторяющегося блока кода, вы можете просто вызвать `printFormattedOutput(out, flags.Format)` в нужном месте вашего кода. Если есть еще вопросы или нужна помощь, не стесняйтесь спрашивать!
User: сделай это методом структуры Announces
Assistant: Конечно! Мы можем сделать метод структуры `Announces`, чтобы обработка формата вывода была встроена в саму структуру. Вот как это можно реализовать:

```go
package resources

import (
	"fmt"
)

type Announces struct {
	Announces []Announce // Предполагается, что Announce — это структура ваших объявлений
}

// Метод для получения отформатированного вывода
func (a *Announces) PrintFormattedOutput(format string) error {
	var outData []byte
	var err error

	switch format {
	case "json":
		outData, err = a.GetJson()
	case "yaml":
		outData, err = a.GetYaml()
	default:
		return fmt.Errorf("недопустимый формат: %s", format)
	}

	if err != nil {
		return err
	}

	fmt.Println(string(outData))
	return nil
}
```

Теперь вы можете вызывать этот метод на экземпляре `Announces` следующим образом:

```go
err := announces.PrintFormattedOutput(flags.Format)
if err != nil {
    // Обработка ошибки
}
```

Таким образом, вы инкапсулируете логику форматирования и вывода в методе структуры `Announces`, что делает код более чистым и удобным для использования. Если у вас есть другие вопросы или нужна дополнительная помощь, дайте знать!
User: hello
User: hello
User: hello
User: hi
User: че молишь
User: ты можешь помочь улучшить мой код, если я прикреплю его файлом?
Assistant: Да, конечно! Вы можете прикрепить файл с вашим кодом, и я помогу вам улучшить его. Жду ваш файл!
User: /Users/g.makarov/golang/bgp-announcer/cmd/cli.go
Assistant: