package logic

import (
	"database/sql"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sevenkeys/database"
	"strings"
)

type Triadic int

const (
	True Triadic = iota
	False
	Either
)

type SearchCriteria struct {
	SetCode         string
	CollectorNumber string
	Promo           Triadic
	Language        string
}

type CardPrintingSearchOptions map[string]string

func GetAllCardPrintingSearchOptions(db *sql.DB, searchCriteria SearchCriteria) (CardPrintingSearchOptions, error) {
	var searchOptions CardPrintingSearchOptions = make(CardPrintingSearchOptions)

	scryfallCards, err := database.GetAllScryfallCards(db)
	if err != nil {
		return searchOptions, err
	}

	for _, scryfallCard := range scryfallCards {
		// Filter based on search criteria
		filter := filterPrinting(scryfallCard, searchCriteria)
		if filter {
			continue
		}

		// Construct search option string
		searchString := fmt.Sprintf("%s (%s %s) [%s]",
			scryfallCard.Name,
			scryfallCard.ScryfallSetCode,
			scryfallCard.CollectorNumber,
			scryfallCard.Language)

		if scryfallCard.IsPromo {
			searchString += " PROMO"
		}

		searchOptions[searchString] = scryfallCard.Id
	}

	return searchOptions, err
}

type StorageSearchOptions map[string]int

func GetAllStorageSearchOptions(db *sql.DB) (StorageSearchOptions, error) {
	var searchOptions StorageSearchOptions = make(StorageSearchOptions)

	storedCards, err := database.GetAllStoredCards(db)
	if err != nil {
		return searchOptions, nil
	}

	for _, storedCard := range storedCards {
		searchString := GetLocationDescription(storedCard)
		searchOptions[searchString] = storedCard.CardLocationId
	}

	return searchOptions, nil
}

func GenericSearch[pk string | int](options map[string]pk) (pk, string, error) {
	var value pk

	cmd := exec.Command("fzf")
	cmd.Stderr = os.Stderr

	fzfStdin, err := cmd.StdinPipe()
	if err != nil {
		return value, "", err
	}

	go func() {
		defer fzfStdin.Close()
		for option, _ := range options {
			io.WriteString(fzfStdin, option+"\n")
		}
	}()

	fzfOutput, err := cmd.Output()
	if err != nil {
		return value, "", err
	}

	searchResult := strings.TrimSuffix(string(fzfOutput), "\n")
	value = options[searchResult]
	return value, searchResult, nil
}