package server

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strconv"
	"strings"

	"streifling.com/jason/sicherheitsunterweisung/packages/data"
	"streifling.com/jason/sicherheitsunterweisung/packages/types"
)

type questionData struct {
	ID int64
	Q  types.Question
	I  int
	J  int
}

func DisplayTable(db *data.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		bs, err := db.ReadAllBriefings()
		if err != nil {
			_ = fmt.Errorf("DisplayTable: %v\n", err)
		}
		template.Must(template.ParseFiles("templates/table.html")).ExecuteTemplate(w, "content", bs)
	}
}

func DisplaySearchResults(db *data.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		bs, err := db.ReadByName(r.PostFormValue("search"))
		if err != nil {
			_ = fmt.Errorf("DisplayResults: db.ReadByName(r.PostFormValue()): %v\n", err)
		}
		template.Must(template.ParseFiles("templates/table.html")).ExecuteTemplate(w, "rows", bs)
	}
}

func DisplayForm(i *int64) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "content", i)
	}
}

func generateUUID() string {
	bs := make([]byte, 2)

	if _, err := rand.Read(bs); err != nil {
		_ = fmt.Errorf("GenerateUUID: rand.Read(bs): %v\n", err)
		return ""
	}

	return hex.EncodeToString(bs)
}

func AddParticipant(i *int64, ls *[]string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		*i++
		login := fmt.Sprintf("%d", *i) + "-" + generateUUID()
		(*ls) = append(*ls, login)
		template.Must(template.ParseFiles("templates/briefing.html")).ExecuteTemplate(w, "new", login)
	}
}

func SubmitForm(db *data.DB, i, j *int64) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		b := new(types.Briefing)

		b.FirstName = r.PostFormValue("instructor-first")
		b.LastName = r.PostFormValue("instructor-last")
		b.Date = r.PostFormValue("date")
		b.Time = r.PostFormValue("time")
		b.State = r.PostFormValue("state")
		b.Location = r.PostFormValue("location")

		for ; *j <= *i; *j++ {
			b.Participants = append(b.Participants, &types.Participant{
				ID: *j,
				Person: types.Person{
					FirstName: r.PostFormValue("participant-first-" + fmt.Sprint(*j)),
					LastName:  r.PostFormValue(("participant-last-" + fmt.Sprint(*j))),
				},
				Company: r.PostFormValue(("participant-company-" + fmt.Sprint(*j))),
			})
		}

		log.Println(b)
		db.WriteBriefing(b)
		bs, err := db.ReadAllBriefings()
		if err != nil {
			_ = fmt.Errorf("SubmitForm: db.ReadAll(): %v\n", err)
		}

		template.Must(template.ParseFiles("templates/table.html")).Execute(w, bs)
	}
}

// TODO: Make it only serve one purpose
func loginIsCorrect(l string, logins *[]string) bool {
	for i, v := range *logins {
		if l == v {
			(*logins) = append((*logins)[:i], (*logins)[i+1:]...)
			return true
		}
	}
	return false
}

func newParticipant(l string) (*types.Participant, error) {
	p := new(types.Participant)

	idInt, err := strconv.Atoi(strings.Split(l, "-")[0])
	if err != nil {
		return nil, fmt.Errorf("newParticipant: strconv.Atoi(idString): %v\n", err)
	}

	p.ID = int64(idInt)
	return p, nil
}

func DisplayParticipantForm(ls *[]string, cp chan<- *types.Participant) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		l := r.PostFormValue("login")

		if loginIsCorrect(l, ls) {
			p, err := newParticipant(l)
			if err != nil {
				http.Error(w, "GetParticipantData: newParticipant(l): "+fmt.Sprint(err), http.StatusInternalServerError)
			}

			cp <- p
			template.Must(template.ParseFiles("templates/participant.html")).ExecuteTemplate(w, "content", p.ID)
		} else {
			template.Must(template.ParseFiles("templates/login.html")).ExecuteTemplate(w, "content", nil)
		}
	}
}

func readAnswer(r *http.Request, p *types.Participant, i int) error {
	v, err := strconv.Atoi(r.PostFormValue("answer"))
	if err != nil {
		return fmt.Errorf("readAnswer: strconv.Atoi(r.PostFormValue(\"answer\")): %v\n", err)
	}

	p.Questions[i].Chosen = v

	return nil
}

func DisplayQuestion(i int, p *types.Participant) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if i == 0 {
			p.FirstName = r.PostFormValue("participant-first-" + fmt.Sprintf("%d", p.ID))
			p.LastName = r.PostFormValue("participant-last-" + fmt.Sprintf("%d", p.ID))
			p.Company = r.PostFormValue("participant-company-" + fmt.Sprintf("%d", p.ID))
		} else {
			if err := readAnswer(r, p, i-1); err != nil {
				http.Error(w, "DisplayQuestion: readAnswer(r, p, i): "+fmt.Sprint(err), http.StatusInternalServerError)
			}
		}

		data := new(questionData)
		data.ID = p.ID
		data.Q = p.Questions[i]
		data.I = i
		data.J = i + 1

		template.Must(template.ParseFiles("templates/question.html")).ExecuteTemplate(w, "content", data)
	}
}

func DisplayTestResults(b *types.Briefing, p *types.Participant) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		numQuestions := len(p.Questions)
		wrongAnswers := make([]int, 0)
		fmt.Println(wrongAnswers)

		if err := readAnswer(r, p, numQuestions-1); err != nil {
			http.Error(w, "DisplayTestResults: readAnswer(r, p, i): "+fmt.Sprint(err), http.StatusInternalServerError)
		}

		for i, q := range p.Questions {
			if q.Chosen != q.Correct {
				wrongAnswers = append(wrongAnswers, i)
			}
		}

		if wrongAnswers == nil {
			b.Participants = append(b.Participants, p)
		} else {
			data := new(questionData)
			data.ID = p.ID
			data.Q = p.Questions[0]
			data.I = 0
			data.J = data.I + 1
			template.Must(template.ParseFiles("templates/question.html")).ExecuteTemplate(w, "content", data)
		}

		template.Must(template.ParseFiles("templates/results.html")).ExecuteTemplate(w, "content", nil)
	}
}
