package db

import (
	"github.com/pocketbase/dbx"
	"github.com/pocketbase/pocketbase/core"
	"github.com/pocketbase/pocketbase/tools/types"
	"htwkalender/data-manager/model"
	"log/slog"
)

// Ensure SeminarGroup satisfies RecordProxy
var _ core.RecordProxy = (*SeminarGroup)(nil)

type SeminarGroups []*SeminarGroup

type SeminarGroup struct {
	core.BaseRecordProxy
}

// Getter and Setter methods

func (s *SeminarGroup) University() string {
	return s.GetString("university")
}
func (s *SeminarGroup) SetUniversity(val string) {
	s.Set("university", val)
}

func (s *SeminarGroup) GroupShortcut() string {
	return s.GetString("shortcut")
}
func (s *SeminarGroup) SetGroupShortcut(val string) {
	s.Set("shortcut", val)
}

func (s *SeminarGroup) GroupId() string {
	return s.GetString("groupId")
}
func (s *SeminarGroup) SetGroupId(val string) {
	s.Set("groupId", val)
}

func (s *SeminarGroup) Course() string {
	return s.GetString("course")
}
func (s *SeminarGroup) SetCourse(val string) {
	s.Set("course", val)
}

func (s *SeminarGroup) Faculty() string {
	return s.GetString("faculty")
}
func (s *SeminarGroup) SetFaculty(val string) {
	s.Set("faculty", val)
}

func (s *SeminarGroup) FacultyId() string {
	return s.GetString("facultyId")
}
func (s *SeminarGroup) SetFacultyId(val string) {
	s.Set("facultyId", val)
}

func (s *SeminarGroup) Semester() string {
	return s.GetString("semester")
}
func (s *SeminarGroup) SetSemester(val string) {
	s.Set("semester", val)
}

func (s *SeminarGroup) Created() types.DateTime {
	return s.GetDateTime("created")
}

func (s *SeminarGroup) Updated() types.DateTime {
	return s.GetDateTime("updated")
}

func (s *SeminarGroup) UniqueKey() string {
	return s.Course() + s.Semester()
}

func NewSeminarGroup(collection *core.Collection, group model.SeminarGroup) (*SeminarGroup, error) {
	// Create a new SeminarGroup instance
	if collection.Name != "groups" {
		return nil, core.ErrInvalidFieldValue
	}

	record := core.NewRecord(collection)
	record.Set("id:autogenerate", "")

	sg := newSeminarGroup(record)
	// Set the fields from the model
	sg.SetUniversity(group.University)
	sg.SetGroupShortcut(group.GroupShortcut)
	sg.SetGroupId(group.GroupId)
	sg.SetCourse(group.Course)
	sg.SetFaculty(group.Faculty)
	sg.SetFacultyId(group.FacultyId)
	sg.SetSemester(group.Semester)

	return sg, nil
}

func newSeminarGroup(record *core.Record) *SeminarGroup {
	sg := &SeminarGroup{}
	sg.SetProxyRecord(record)
	return sg
}

// ToModel Model conversion
func (s *SeminarGroup) ToModel() model.SeminarGroup {
	return model.SeminarGroup{
		University:    s.University(),
		GroupShortcut: s.GroupShortcut(),
		GroupId:       s.GroupId(),
		Course:        s.Course(),
		Faculty:       s.Faculty(),
		FacultyId:     s.FacultyId(),
		Semester:      s.Semester(),
	}
}

func (s *SeminarGroups) ToModelArray() []model.SeminarGroup {
	models := make([]model.SeminarGroup, len(*s))
	for i, group := range *s {
		models[i] = group.ToModel()
	}
	return models
}

func (s *SeminarGroup) FromModel(m model.SeminarGroup) {
	s.SetUniversity(m.University)
	s.SetGroupShortcut(m.GroupShortcut)
	s.SetGroupId(m.GroupId)
	s.SetCourse(m.Course)
	s.SetFaculty(m.Faculty)
	s.SetFacultyId(m.FacultyId)
	s.SetSemester(m.Semester)
}

func (s *SeminarGroups) FromModelArray(m model.SeminarGroups) SeminarGroups {
	groups := make(SeminarGroups, len(m))
	for i, group := range m {
		groups[i] = &SeminarGroup{}
		groups[i].FromModel(group)
	}
	return groups
}

func FindCourseByCourseName(app core.App, courseName string) (model.SeminarGroup, error) {
	group := &SeminarGroup{}
	err := app.RecordQuery("groups").
		AndWhere(dbx.NewExp("course = {:course}", dbx.Params{"course": courseName})).
		Limit(1).
		One(group)

	if err != nil {
		return model.SeminarGroup{}, err
	}

	return group.ToModel(), nil
}

func GetAllCourses(app core.App) ([]string, error) {
	var groups []*SeminarGroup
	err := app.RecordQuery("groups").All(&groups)
	if err != nil {
		return nil, err
	}

	var courseArray []string
	for _, g := range groups {
		courseArray = append(courseArray, g.Course())
	}

	return courseArray, nil
}

func GetAllCoursesForSemester(app core.App, semester string) ([]model.SeminarGroup, error) {
	var groups []*SeminarGroup
	err := app.RecordQuery("groups").
		AndWhere(dbx.NewExp("semester = {:semester}", dbx.Params{"semester": semester})).
		All(&groups)

	if err != nil {
		return nil, err
	}

	var models []model.SeminarGroup
	for _, g := range groups {
		models = append(models, g.ToModel())
	}
	return models, nil
}

func GetAllCoursesForSemesterWithEvents(app core.App, semester string) ([]string, error) {
	var results []struct {
		Course string `db:"course"`
	}

	err := app.DB().NewQuery(`
		SELECT DISTINCT course FROM events WHERE semester = {:semester}
	`).Bind(dbx.Params{"semester": semester}).All(&results)

	if err != nil {
		return nil, err
	}

	var courses []string
	for _, r := range results {
		courses = append(courses, r.Course)
	}

	return courses, nil
}

func SaveGroups(app core.App, seminarGroups []model.SeminarGroup) (model.SeminarGroups, error) {
	// Delete all existing
	execute, err := app.DB().Delete("groups", dbx.NewExp("1 = 1")).Execute()
	if err != nil {
		return nil, err
	}
	// Check if to delete was successful
	rowCount, _ := execute.RowsAffected()

	// Gruppen-Collection abrufen
	collection, err := app.FindCollectionByNameOrId("groups")
	if err != nil {
		return nil, err
	}

	// Seminargruppen in die Datenbank speichern
	savedGroups := SeminarGroups{}
	for _, group := range seminarGroups {

		dbSeminarGroup, recordErr := NewSeminarGroup(collection, group)
		if recordErr != nil {
			return nil, err
		}

		saveErr := app.Save(dbSeminarGroup)
		if saveErr != nil {
			return nil, saveErr
		}
		savedGroups = append(savedGroups, dbSeminarGroup)
	}
	slog.Info("Saved all groups to the database", "insert", len(savedGroups), "deleted", rowCount)

	return savedGroups.ToModelArray(), nil

}
