package commands

import (
	"errors"
	"strings"

	"github.com/emersion/go-imap"
)

// Fetch is a FETCH command, as defined in RFC 3501 section 6.4.5.
type Fetch struct {
	SeqSet *imap.SeqSet
	Items  []string
}

func (cmd *Fetch) Command() *imap.Command {
	items := make([]interface{}, len(cmd.Items))
	for i, item := range cmd.Items {
		if section, err := imap.NewBodySectionName(item); err == nil {
			items[i] = section
		} else {
			items[i] = item
		}
	}

	return &imap.Command{
		Name:      imap.Fetch,
		Arguments: []interface{}{cmd.SeqSet, items},
	}
}

func (cmd *Fetch) Parse(fields []interface{}) error {
	if len(fields) < 2 {
		return errors.New("No enough arguments")
	}

	seqset, ok := fields[0].(string)
	if !ok {
		return errors.New("Sequence set must be a string")
	}

	var err error
	if cmd.SeqSet, err = imap.NewSeqSet(seqset); err != nil {
		return err
	}

	switch items := fields[1].(type) {
	case string: // A macro or a single item
		switch strings.ToUpper(items) {
		case "ALL":
			cmd.Items = []string{"FLAGS", "INTERNALDATE", "RFC822.SIZE", "ENVELOPE"}
		case "FAST":
			cmd.Items = []string{"FLAGS", "INTERNALDATE", "RFC822.SIZE"}
		case "FULL":
			cmd.Items = []string{"FLAGS", "INTERNALDATE", "RFC822.SIZE", "ENVELOPE", "BODY"}
		default:
			cmd.Items = []string{strings.ToUpper(items)}
		}
	case []interface{}: // A list of items
		cmd.Items = make([]string, len(items))
		for i, v := range items {
			item, _ := v.(string)
			cmd.Items[i] = strings.ToUpper(item)
		}
	default:
		return errors.New("Items must be either a string or a list")
	}

	return nil
}
