package controllers

import (
	"fmt"
	"math"
	"strconv"
	"time"
	"zatobay_api/database"
	"zatobay_api/models"

	"github.com/gofiber/fiber/v2"

	datatable "zatobay_api/utils/datatable"
)

type FilterAjaxTeacher struct {
	TeacherName string `json:"teacher_name" url:"teacher_name" query:"teacher_name"`
	Page        string `json:"page" url:"page" query:"page"`
	PerPage     string `json:"length" url:"length" query:"length"`
	Sort        string `json:"column" url:"column" query:"column"`
	SortDir     string `json:"dir" url:"dir" query:"dir"`
	Draw        string `json:"draw" url:"draw" query:"draw"`
}

func CreateTeacher(c *fiber.Ctx) error {

	// user auth

	var data map[string]string

	if err := c.BodyParser(&data); err != nil {
		return c.Status(400).JSON(err.Error())
	}
	school_id, err := strconv.Atoi(data["school_id"])
	if err != nil {
		return err
	}

	teacher_info := models.Teacher{
		SchoolId:    school_id,
		TeacherName: data["teacher_name"],
		CreatedAt:   time.Now(),
		UpdatedAt:   time.Now(),
	}

	res := database.DB.Create(&teacher_info)
	if res.Error != nil {
		return c.Status(400).JSON(fiber.Map{
			"status": "error",
			"error":  res.Error,
		})
	}
	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   teacher_info,
	})
}

func GetTeacher(c *fiber.Ctx) error {

	var teacher_info []models.Teacher

	result := database.DB.Find(&teacher_info)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   teacher_info,
	})
}

func GetTeacherById(c *fiber.Ctx) error {

	var teacher_info models.Teacher

	paramsId := c.Params("id")

	id_int, err := strconv.Atoi(paramsId)

	if err != nil {
		return err
	}

	result := database.DB.Find(&teacher_info, id_int)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   teacher_info,
	})
}

func GetTeacherBySchoolId(c *fiber.Ctx) error {

	var teacher_info []models.Teacher

	paramsId := c.Params("id")

	school_id_int, err := strconv.Atoi(paramsId)

	if err != nil {
		return err
	}

	result := database.DB.Where("school_id = ?", school_id_int).Find(&teacher_info)
	if result.RowsAffected == 0 {
		return c.Status(200).JSON(fiber.Map{
			"status": "empty teacher",
			"data":   teacher_info,
		})
	}

	return c.Status(200).JSON(fiber.Map{
		"status": "success",
		"data":   teacher_info,
	})
}

func UpdateTeacher(c *fiber.Ctx) error {
	var data map[string]string

	if err := c.BodyParser(&data); err != nil {
		return c.Status(400).JSON(err.Error())
	}

	id := c.Params("id")
	id_int, err := strconv.Atoi(id)

	if err != nil {
		return err
	}

	teacher := models.Teacher{
		TeacherName: data["teacher_name"],
		UpdatedAt:   time.Now(),
	}

	result := database.DB.Where("id = ?", id_int).Updates(&teacher)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"message": "success update teacher, id :" + id,
		"data":    teacher,
		"status":  "success",
	})
}

func DeleteTeacher(c *fiber.Ctx) error {

	id := c.Params("id")
	id_int, err := strconv.Atoi(id)

	if err != nil {
		id_int = -1
	}

	var Teacher models.Teacher

	result := database.DB.Delete(&Teacher, id_int)

	if result.RowsAffected == 0 {
		return c.SendStatus(404)
	}

	return c.Status(200).JSON(fiber.Map{
		"message": "success delete teacher, id :" + id,
		"status":  "success",
	})
}

func TeacherAjaxListBySchoolId(c *fiber.Ctx) error {

	filterAjax := new(FilterAjaxTeacher)

	id_school_int, err := strconv.Atoi(c.Params("id"))
	if err != nil {
		return err
	}

	if err := c.QueryParser(filterAjax); err != nil {
		return c.Status(400).JSON(err.Error())
	}

	page, err := strconv.Atoi(filterAjax.Page)
	if err != nil {
		page = 1
	}
	perPage, err := strconv.Atoi(filterAjax.PerPage)
	if err != nil {
		perPage = 10
	}

	Teacher := models.Teacher{
		TeacherName: filterAjax.TeacherName,
	}

	var sort map[string]string
	sort = make(map[string]string)
	if filterAjax.Sort != "" {
		if filterAjax.SortDir == "" {
			sort[filterAjax.Sort] = "desc"
		} else {
			sort[filterAjax.Sort] = filterAjax.SortDir
		}
	}
	limit := perPage
	offset := (page - 1) * limit

	data, total, err := TeacherQueryAjaxList(Teacher, limit, offset, sort, id_school_int)

	if err != nil {
		return c.Status(400).JSON(err.Error())
	}
	pages := math.Ceil(float64(*total) / float64(perPage))
	meta := datatable.MetaDataTable{
		CurrentPage: page,
		From:        offset + 1,
		LastPage:    int(pages),
		Path:        "",
		PerPage:     fmt.Sprintf("%v", limit),
		To:          offset + limit,
		Total:       int(*total),
	}

	datatableFormat := datatable.DataTable{
		Meta: datatable.MetaDataTable{
			CurrentPage: page,
			From:        0,
			LastPage:    1,
			Path:        *datatable.BuildUrlForLink(c.Request(), 0),
			PerPage:     strconv.Itoa(perPage),
			To:          0,
			Total:       0,
		},
		Data: nil,
		Links: datatable.LinkDatatable{
			First: *datatable.BuildUrlForLink(c.Request(), 1),
			Last:  nil,
			Next:  nil,
			Prev:  nil,
		},
		Payload: filterAjax,
	}

	if err == nil {
		var dataResponseTeacher []models.Teacher

		for _, data := range data {
			dataResponseTeacher = append(dataResponseTeacher, data)
		}

		datatableFormat.Data = dataResponseTeacher
		meta.Path = *datatable.BuildUrlForLink(c.Request(), 0)
		datatableFormat.Meta = meta
		datatableFormat.Links = datatable.BuildLinksData(c.Request(), meta)
	}

	return c.JSON(fiber.Map{
		"status": "success",
		"data":   datatableFormat,
	})
}

func TeacherQueryAjaxList(filter models.Teacher, limit, offset int, sort map[string]string, id_teacher_int int) ([]models.Teacher, *int64, error) {
	var (
		result []models.Teacher
		count  int64
	)

	query := database.DB.Where(filter).Where("school_id = ?", id_teacher_int)
	if sort == nil {
		query = query.Order("id")
	} else {
		for key, val := range sort {
			query = query.Order(fmt.Sprintf("%s %s", key, val))
		}
	}
	query = query.Offset(offset).Limit(limit).Find(&result)
	fmt.Println(query)
	if query.Error != nil {
		return nil, nil, query.Error
	}
	dbCount := database.DB.Table("teachers").Where(filter).Select("id").Count(&count)
	if dbCount.Error != nil {
		return nil, nil, dbCount.Error
	}
	return result, &count, nil

}
