// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package init

import (
	"errors"
	"fmt"

	"github.com/charmbracelet/huh"

	"git.secluded.site/lune/internal/config"
)

func manageNotebooks(cfg *config.Config) error {
	nav := manageNotebooksAsStep(cfg)
	if nav == navQuit {
		return errQuit
	}

	return nil
}

// manageNotebooksAsStep runs notebooks management as a wizard step with Back/Next navigation.
func manageNotebooksAsStep(cfg *config.Config) wizardNav {
	for {
		options := buildNotebookStepOptions(cfg.Notebooks)

		choice, err := runListSelect(
			"Notebooks",
			"Notebooks organize your notes in Lunatask.",
			options,
		)
		if err != nil {
			return navQuit
		}

		switch choice {
		case choiceBack:
			return navBack
		case choiceNext:
			return navNext
		case choiceAdd:
			if err := addNotebook(cfg); errors.Is(err, errQuit) {
				return navQuit
			}
		default:
			idx, ok := parseEditIndex(choice)
			if !ok {
				continue
			}

			if err := manageNotebookActions(cfg, idx); errors.Is(err, errQuit) {
				return navQuit
			}
		}
	}
}

func buildNotebookStepOptions(notebooks []config.Notebook) []huh.Option[string] {
	options := []huh.Option[string]{
		huh.NewOption("Add new notebook", choiceAdd),
	}

	for idx, notebook := range notebooks {
		label := fmt.Sprintf("%s (%s)", notebook.Name, notebook.Key)
		options = append(options, huh.NewOption(label, fmt.Sprintf("edit:%d", idx)))
	}

	options = append(options,
		huh.NewOption("← Back", choiceBack),
		huh.NewOption("Next →", choiceNext),
	)

	return options
}

func addNotebook(cfg *config.Config) error {
	notebook, err := editNotebook(nil, cfg)
	if err != nil {
		if errors.Is(err, errBack) {
			return nil
		}

		return err
	}

	cfg.Notebooks = append(cfg.Notebooks, *notebook)

	return nil
}

func manageNotebookActions(cfg *config.Config, idx int) error {
	if idx < 0 || idx >= len(cfg.Notebooks) {
		return fmt.Errorf("%w: notebook %d", errIndexOutRange, idx)
	}

	notebook := &cfg.Notebooks[idx]

	action, err := runActionSelect(fmt.Sprintf("Notebook: %s (%s)", notebook.Name, notebook.Key), false)
	if err != nil {
		return err
	}

	switch action {
	case itemActionEdit:
		updated, err := editNotebook(notebook, cfg)
		if err != nil {
			if errors.Is(err, errBack) {
				return nil
			}

			return err
		}

		if updated != nil {
			cfg.Notebooks[idx] = *updated
		}
	case itemActionDelete:
		return deleteNotebook(cfg, idx)
	case itemActionNone, itemActionGoals:
		// User cancelled or went back; goals not applicable here
	}

	return nil
}

func editNotebook(existing *config.Notebook, cfg *config.Config) (*config.Notebook, error) {
	notebook := config.Notebook{}
	if existing != nil {
		notebook = *existing
	}

	err := runItemForm(&notebook.Name, &notebook.Key, &notebook.ID, itemFormConfig{
		itemType:         "notebook",
		namePlaceholder:  "Gaelic Notes",
		keyPlaceholder:   "gaelic",
		keyValidator:     validateNotebookKey(cfg, existing),
		supportsDeepLink: true,
	})
	if err != nil {
		return nil, err
	}

	return &notebook, nil
}

func validateNotebookKey(cfg *config.Config, existing *config.Notebook) func(string) error {
	return func(input string) error {
		if err := validateKeyFormat(input); err != nil {
			return err
		}

		for idx := range cfg.Notebooks {
			if existing != nil && &cfg.Notebooks[idx] == existing {
				continue
			}

			if cfg.Notebooks[idx].Key == input {
				return errKeyDuplicate
			}
		}

		return nil
	}
}

func deleteNotebook(cfg *config.Config, idx int) error {
	if idx < 0 || idx >= len(cfg.Notebooks) {
		return fmt.Errorf("%w: notebook %d", errIndexOutRange, idx)
	}

	notebook := cfg.Notebooks[idx]

	var confirm bool

	err := huh.NewConfirm().
		Title(fmt.Sprintf("Delete notebook '%s'?", notebook.Name)).
		Description("This cannot be undone.").
		Affirmative("Delete").
		Negative("Cancel").
		Value(&confirm).
		Run()
	if err != nil {
		if errors.Is(err, huh.ErrUserAborted) {
			return errQuit
		}

		return err
	}

	if confirm {
		cfg.Notebooks = append(cfg.Notebooks[:idx], cfg.Notebooks[idx+1:]...)
		if cfg.Defaults.Notebook == notebook.Key {
			cfg.Defaults.Notebook = ""
		}
	}

	return nil
}
