package api

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"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"
	"gogs.carducci-dante.gov.it/karmen/datasource/edt"
)

var (
	selectUniqueSubjectTeachers = `
SELECT DISTINCT teachers.* FROM activities 
INNER JOIN subjects ON subjects.id=activities.subject_id 
INNER JOIN teachers on teachers.id=activities.teacher_id
WHERE subject_id=? GROUP BY activities.teacher_id ORDER BY teachers.Surname;
`
)

func subjectsHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		var subjects []*orm.Subject

		if err := orm.DB().Order("name").Find(&subjects).Error; err != nil {
			panic(err)
		}

		for _, subject := range subjects {
			orm.DB().Raw(selectUniqueSubjectTeachers, subject.ID).Scan(&subject.Teachers)
		}

		if err := renderer.Render(w, "base", "subjects", subjects); err != nil {
			panic(err)
		}
	}
	return http.HandlerFunc(fn)
}

func subjectsShowHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		var subject orm.Subject

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

		orm.DB().Raw(selectUniqueSubjectTeachers, mux.Vars(r)["id"]).Scan(&subject.Teachers)

		if err := renderer.Render(w, "base", "subjects_show", subject); err != nil {
			panic(err)
		}
	}
	return http.HandlerFunc(fn)
}

func subjectsAddHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			var data struct {
				Update    bool
				SubmitUrl template.URL
			}
			data.SubmitUrl = template.URL(fmt.Sprintf("/subjects/add"))
			if err := renderer.Render(w, "base", "subjects_add_update", data); err != nil {
				panic(err)
			}
		} else if r.Method == "POST" {
			var subject orm.Subject
			if err := r.ParseForm(); err != nil {
				panic(err)
			}

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

			orm.DB().NewRecord(subject)

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

			http.Redirect(w, r, fmt.Sprintf("/subjects/%d", subject.ID), http.StatusSeeOther)
		}

	}
	return http.HandlerFunc(fn)
}

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

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

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

		data.RedirectUrl = "/subjects"

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

func subjectsUpdateHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			var data struct {
				Update    bool
				SubmitUrl template.URL
				Subject   orm.Subject
			}

			if err := orm.DB().First(&data.Subject, mux.Vars(r)["id"]).Error; err != nil {
				panic(err)
			}
			data.Update = true
			data.SubmitUrl = template.URL(fmt.Sprintf("/subjects/%d/update", data.Subject.ID))
			if err := renderer.Render(w, "base", "subjects_add_update", data); err != nil {
				panic(err)
			}
		} else if r.Method == "POST" {
			var subject orm.Subject

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

			if err := r.ParseForm(); err != nil {
				panic(err)
			}

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

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

			var data struct {
				Subjects []*orm.Subject
			}

			data.Subjects = make([]*orm.Subject, 0)
			if err := orm.DB().Find(&data.Subjects).Error; err != nil {
				panic(err)
			}

			if err := renderer.Render(w, "base", "subjects", data); err != nil {
				panic(err)
			}
		}

	}
	return http.HandlerFunc(fn)
}

func subjectsImportHandler() http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		r.ParseMultipartForm(32 << 20)
		file, _, err := r.FormFile("subjects_import")
		if err != nil {
			panic(err)
		}
		defer file.Close()
		data, err := ioutil.ReadAll(file)
		if err != nil {
			panic(err)
		}
		if importer, err := edt.NewImporter(
			string(data),
			map[string]string{
				"NOME": "name",
			},
		); err != nil {
			panic(err)
		} else {
			if err := orm.Import(&orm.Subject{}, importer); err != nil {
				panic(err)
			}
			http.Redirect(w, r, "/subjects", http.StatusSeeOther)
		}
	}
	return http.HandlerFunc(fn)
}
