package cli

import (
	"fmt"
	"log"

	"gogs.inhome.blapointe.com/ana-ledger/src/ledger"
)

type Query struct{}

func BuildQuery(config Config, args args) (ledger.Like, error) {
	var result ledger.Like
	var err error
	func() {
		defer func() {
			if err := recover(); err != nil {
				err = fmt.Errorf("panicked: %v", err)
			}
		}()
		result, err = buildQuery(config, args)
	}()
	return result, err
}

func buildQuery(config Config, args args) (ledger.Like, error) {
	likeName := func(s string) ledger.Like {
		return ledger.LikeName(s)
	}
	andLike := func(a, b ledger.Like) ledger.Like {
		return (ledger.Likes{a, b}).All
	}
	orLike := func(a, b ledger.Like) ledger.Like {
		return (ledger.Likes{a, b}).Any
	}
	notLike := func(a ledger.Like) ledger.Like {
		return ledger.LikeNot(a)
	}

	if !args.more() {
		return likeName(""), nil
	}
	like := likeName("ajskfdlsjfkdasj")

	for args.more() {
		switch args.peek() {
		case "and":
			args.pop()
			var and ledger.Like
			switch args.peek() {
			case "not":
				args.pop()
				log.Println("and not", args.peek())
				and = notLike(likeName(args.pop()))
			default:
				log.Println("and ", args.peek())
				and = likeName(args.pop())
			}
			like = andLike(like, and)
		case "not":
			args.pop()
			log.Println("or not ", args.peek())
			like = orLike(like, notLike(
				likeName(args.pop()),
			))
		default:
			log.Println("or ", args.peek())
			like = orLike(like,
				likeName(args.pop()),
			)
		}
	}

	return like, nil
}

type args []string

func (args *args) pop() string {
	if !args.more() {
		panic("expected more arguments")
	}
	first := ""
	if len(*args) > 0 {
		first = (*args)[0]
		*args = (*args)[1:]
	}
	return first
}

func (args *args) peek() string {
	if len(*args) == 0 {
		return ""
	}
	return (*args)[0]
}

func (args *args) more() bool {
	return len(*args) > 0
}
