package api

import (
	"encoding/json"
	"fmt"
	"html/template"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/gorilla/schema"

	"gogs.carducci-dante.gov.it/karmen/core/orm"
	"gogs.carducci-dante.gov.it/karmen/core/renderer"
)

func saveActivity(r *http.Request, activity *orm.Activity) {
	var (
		class   orm.Class
		subject orm.Subject
	)
	if err := r.ParseForm(); err != nil {
		panic(err)
	}

	decoder := schema.NewDecoder()
	if err := decoder.Decode(activity, r.PostForm); err != nil {
		panic(err)
	}

	if err := orm.DB().First(&class, activity.ClassID).Error; err != nil {
		panic(err)
	}

	if err := orm.DB().First(&subject, activity.SubjectID).Error; err != nil {
		panic(err)
	}

	activity.Name = fmt.Sprintf("%s %s %dh", class.Name, subject.Name, activity.Hours)

	if err := orm.DB().Save(activity).Error; err != nil {
		panic(err)
	}

}

func activitiesHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		var data struct {
			Activities []orm.Activity
		}
		if err := orm.DB().Find(&data.Activities).Error; err != nil {
			panic(err)
		}

		if err := orm.DB().Preload("Subject").Preload("Teacher").Preload("Class").Find(&data.Activities).Error; err != nil {
			panic(err)
		}
		if err := renderer.Render(w, "base", "activities", data); err != nil {
			panic(err)
		}
	}
	return http.HandlerFunc(fn)
}

func activitiesAddHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			var data struct {
				Update      bool
				AllTeachers []orm.Teacher
				AllClasses  []orm.Class
				AllSubjects []orm.Subject
				SubmitUrl   template.URL
			}
			data.SubmitUrl = template.URL(fmt.Sprintf("/activities/add"))

			if err := orm.DB().Find(&data.AllTeachers).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().Find(&data.AllClasses).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().Find(&data.AllSubjects).Error; err != nil {
				panic(err)
			}

			if err := renderer.Render(w, "base", "activities_add_update", data); err != nil {
				panic(err)
			}
		} else if r.Method == "POST" {
			var activity orm.Activity

			if err := orm.DB().Create(&activity).Error; err != nil {
				panic(err)
			}

			saveActivity(r, &activity)

			http.Redirect(w, r, fmt.Sprintf("/activities"), http.StatusSeeOther)
		}

	}
	return http.HandlerFunc(fn)
}

func activitiesDeleteHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		var activity orm.Activity
		if err := orm.DB().First(&activity, mux.Vars(r)["id"]).Error; err != nil {
			panic(err)
		}

		if err := orm.DB().Delete(&activity).Error; err != nil {
			panic(err)
		}

		var data struct {
			RedirectUrl string `json:"redirect_url"`
		}

		// Handle associations

		if activity.TeacherID != 0 {
			var (
				class   orm.Class
				subject orm.Class
				teacher orm.Teacher
			)
			if err := orm.DB().First(&teacher, activity.TeacherID).Error; err != nil {
				panic(err)
			}

			teacher.CalcHours(orm.DB())
			orm.DB().Save(&teacher)

			if err := orm.DB().First(&class, activity.ClassID).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().First(&subject, activity.SubjectID).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().Model(&teacher).Association("Classes").Delete(class).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().Model(&teacher).Association("Subjects").Delete(subject).Error; err != nil {
				panic(err)
			}
		}

		data.RedirectUrl = "/activities"

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(data)
	}
	return http.HandlerFunc(fn)
}

func activitiesUpdateHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			var data struct {
				Update          bool
				SubmitUrl       template.URL
				Activity        orm.Activity
				AllTeachers     []orm.Teacher
				AllSubjects     []orm.Subject
				AllClasses      []orm.Class
				SelectedTeacher map[uint]string
				SelectedSubject map[uint]string
				SelectedClass   map[uint]string
			}

			if err := orm.DB().First(&data.Activity, mux.Vars(r)["id"]).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().Find(&data.AllTeachers).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().Find(&data.AllSubjects).Error; err != nil {
				panic(err)
			}

			if err := orm.DB().Find(&data.AllClasses).Error; err != nil {
				panic(err)
			}

			if id := data.Activity.TeacherID; id != 0 {
				data.SelectedTeacher = make(map[uint]string)
				data.SelectedTeacher[id] = "selected"
			}

			data.SelectedClass = make(map[uint]string)
			data.SelectedClass[data.Activity.ClassID] = "selected"

			data.SelectedSubject = make(map[uint]string)
			data.SelectedSubject[data.Activity.SubjectID] = "selected"

			data.Update = true
			data.SubmitUrl = template.URL(fmt.Sprintf("/activities/%d/update", data.Activity.ID))

			if err := renderer.Render(w, "base", "activities_add_update", data); err != nil {
				panic(err)
			}
		} else if r.Method == "POST" {
			var activity orm.Activity

			if err := orm.DB().First(&activity, mux.Vars(r)["id"]).Error; err != nil {
				panic(err)
			}

			saveActivity(r, &activity)

			http.Redirect(w, r, fmt.Sprintf("/activities"), http.StatusSeeOther)
		}

	}
	return http.HandlerFunc(fn)
}
