package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"strings"
	"time"
)

func Terminal(db DB) error {
	user := IDU(os.Getenv("USER"))
	failed, err := Review(db, user)
	if err != nil {
		return err
	}
	for len(failed) > 0 {
		for i := len(failed) - 1; i >= 0; i-- {
			if _, passed, err := ReviewQ(db, user, failed[i]); err != nil {
				return err
			} else if passed == CMD_PASS {
				return nil
			} else if passed != CMD_FAIL {
				failed = append(failed[:i], failed[i+1:]...)
			}
		}
	}
	return nil
}

func Review(db DB, user IDU) ([]IDQ, error) {
	failed := []IDQ{}

	for q, _ := range db.HistoryOf(user) {
		if time.Until(db.Next(user, q)) > 0 {
			continue
		}
		response, passed, err := ReviewQ(db, user, q)
		if err != nil {
			return nil, err
		}
		switch passed {
		case CMD_QUIT:
			return nil, nil
		case CMD_FAIL:
			failed = append(failed, q)
			if err := db.PushAnswer(user, q, Renderable(response), false); err != nil {
				return nil, err
			}
		case CMD_PASS:
			if err := db.PushAnswer(user, q, Renderable(response), true); err != nil {
				return nil, err
			}
		}
		fmt.Println()
	}
	return failed, nil
}

func ReviewQ(db DB, user IDU, q IDQ) (string, string, error) {
	question := db.Question(q)
	fmt.Printf("> Q: %s\n", question.Q.ToString(db.UserResolution(user)))
	fmt.Printf("\n")
	fmt.Printf("> %+v\n", question.Tags)
	var response string
	gotAClue := false
	for i := range question.Clues {
		if i == 0 {
			fmt.Printf("> /clue for a clue\n")
		}
		response = readline()
		if response != "/clue" {
			break
		}
		gotAClue = true
		fmt.Printf("> %s", question.Clues[i].ToString(db.UserResolution(user)))
		if i+1 < len(question.Clues) {
			fmt.Printf(" | /clue for another clue")
		}
		fmt.Printf("\n")
	}
	if len(question.Clues) == 0 || response == "/clue" {
		response = readline()
	}
	if !gotAClue && len(question.Solution) > 0 && question.Solution[0].ToString(1) == response {
		return response, CMD_PASS, nil
	}
	if len(question.Solution) > 0 {
		fmt.Printf("> Solution:")
		for i := range question.Solution {
			fmt.Printf("\n\t%s", question.Solution[i].ToString(db.UserResolution(user)))
		}
		fmt.Println()
	}
	if id, _ := db.LastAnswer(user, q); id == "" {
	} else if lastAnswer := db.Answer(id); lastAnswer.A != "" {
		fmt.Printf("> Last time, you responded:\n\t%s\n", lastAnswer.A)
	}
	fmt.Printf("> Did you pass this time? [%s%s%s%s]\n",
		strings.ToUpper(CMD_PASS),
		strings.ToLower(CMD_FAIL),
		strings.ToLower(CMD_SKIP),
		strings.ToLower(CMD_QUIT),
	)
	switch strings.ToLower(readline()) {
	case CMD_SKIP:
		return response, CMD_SKIP, nil
	case CMD_FAIL:
		return response, CMD_FAIL, nil
	case CMD_QUIT:
		return response, CMD_QUIT, nil
	}
	return response, CMD_PASS, nil
}

func readline() string {
	fmt.Printf("\t")
	reader := bufio.NewReader(os.Stdin)
	text, _ := reader.ReadString('\n')
	return strings.TrimSpace(text)
}

func (renderable Renderable) ToString(resolution int) string {
	s := string(renderable)
	if !strings.HasPrefix(s, "img:") {
		return s
	}
	buff := bytes.NewBuffer(nil)
	ViewAt(buff, s[4:], resolution)
	return string(buff.Bytes())
}
