package orm

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/jinzhu/gorm"
	"gogs.carduccidante.edu.it/karmen/core/renderer"
)

type Activity struct {
	gorm.Model

	Name string

	Class         *Class
	Teacher       *Teacher
	SupplyTeacher *Teacher
	Subject       *Subject
	Student       *Student

	GroupActivity      bool
	GroupActivityHours int `schema:"group_activity_hours"`

	ClassID         uint `schema:"class_id"`
	TeacherID       uint `schema:"teacher_id"`
	SupplyTeacherID uint `schema:"supply_teacher_id"`
	SubjectID       uint `schema:"subject_id"`
	StudentID       uint `schema:"student_id"`

	Hours int

	AllClasses  []*Class   `gorm:"-"`
	AllSubjects []*Subject `gorm:"-"`
	AllTeachers []*Teacher `gorm:"-"`
	AllStudents []*Student `gorm:"-"`

	SelectedStudent       map[uint]string `gorm:"-"`
	SelectedTeacher       map[uint]string `gorm:"-"`
	SelectedSupplyTeacher map[uint]string `gorm:"-"`
	SelectedSubject       map[uint]string `gorm:"-"`
	SelectedClass         map[uint]string `gorm:"-"`
}

func (a *Activity) GetID() uint { return a.ID }

func (a *Activity) String() string {
	var result string

	result = a.Subject.Name

	if a.Class != nil {
		result += " " + a.Class.Name
	}

	if a.SupplyTeacher != nil {
		result += fmt.Sprintf(" (SUPPL %s)", a.SupplyTeacher.String())
	}

	result += " " + strconv.Itoa(a.Hours) + "h"

	return result
}

func (a *Activity) Create(args map[string]string, r *http.Request) (interface{}, error) {
	if r.Method == "GET" {
		activity := new(Activity)

		if err := DB().Find(&activity.AllClasses).Error; err != nil {
			return nil, err
		}

		if err := DB().Find(&activity.AllSubjects).Error; err != nil {
			return nil, err
		}

		if err := DB().Find(&activity.AllTeachers).Error; err != nil {
			return nil, err
		}

		if err := DB().Find(&activity.AllStudents).Error; err != nil {
			return nil, err
		}

		return activity, nil
	} else {
		activity := new(Activity)
		err := renderer.Decode(activity, r)
		if err != nil {
			return nil, err
		}
		activity, err = CreateActivity(activity)
		if err != nil {
			return nil, err
		}

		return activity, nil
	}
}

func (a *Activity) Read(args map[string]string, r *http.Request) (interface{}, error) {
	var activity Activity

	id := args["id"]

	if err := DB().Preload("Student").Preload("Teacher").Preload("Subject").Preload("Class").First(&activity, id).Error; err != nil {
		return nil, err
	}

	return &activity, nil
}

func (a *Activity) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
	var activities []*Activity

	if err := DB().Preload("Teacher").Preload("Subject").Preload("Class").Order("name").Find(&activities).Error; err != nil {
		return nil, err
	}

	return activities, nil
}

func (a *Activity) Update(args map[string]string, r *http.Request) (interface{}, error) {
	if r.Method == "GET" {
		result, err := a.Read(args, r)
		if err != nil {
			return nil, err
		}

		activity := result.(*Activity)

		if err := DB().Find(&activity.AllClasses).Error; err != nil {
			return nil, err
		}

		if err := DB().Find(&activity.AllSubjects).Error; err != nil {
			return nil, err
		}

		if err := DB().Find(&activity.AllTeachers).Error; err != nil {
			return nil, err
		}

		if err := DB().Find(&activity.AllStudents).Error; err != nil {
			return nil, err
		}

		activity.SelectedTeacher = make(map[uint]string)
		activity.SelectedTeacher[activity.TeacherID] = "selected"

		activity.SelectedSupplyTeacher = make(map[uint]string)
		activity.SelectedSupplyTeacher[activity.SupplyTeacherID] = "selected"

		activity.SelectedStudent = make(map[uint]string)
		activity.SelectedStudent[activity.StudentID] = "selected"

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

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

		return activity, nil
	} else {
		activity, err := a.Read(args, r)
		if err != nil {
			return nil, err
		}

		activity.(*Activity).GroupActivity = false

		err = renderer.Decode(activity, r)
		if err != nil {
			return nil, err
		}
		_, err = SaveActivity(activity)
		if err != nil {
			return nil, err
		}
		activity, err = a.Read(args, r)
		if err != nil {
			return nil, err
		}

		return activity.(*Activity), nil
	}
}

func (a *Activity) Delete(args map[string]string, r *http.Request) (interface{}, error) {
	activity, err := a.Read(args, r)
	if err != nil {
		return nil, err
	}
	if err := DB().Unscoped().Delete(activity.(*Activity)).Error; err != nil {
		return nil, err
	}
	return activity.(*Activity), nil
}

func SaveActivity(activity interface{}) (interface{}, error) {
	if err := DB().Omit(
		"Class",
		"Teacher",
		"Subject",
		"SupplyTeacher",
		"Student",
	).Save(activity).Error; err != nil {
		return nil, err
	}
	return activity, nil
}

func CreateActivity(activity *Activity) (*Activity, error) {
	if err := DB().Create(activity).Error; err != nil {
		return nil, err
	}
	return activity, nil
}
