package controller

import (
	"fmt"
	"net/http"
	"opencatd-open/internal/dto"
	"opencatd-open/internal/model"
	"opencatd-open/internal/utils"
	"strconv"
	"strings"

	"github.com/duke-git/lancet/v2/slice"
	"github.com/gin-gonic/gin"
)

func (a Api) Register(c *gin.Context) {
	req := new(dto.User)
	err := c.ShouldBind(&req)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}

	err = a.userService.Register(c, &model.User{
		Username: req.Username,
		Password: req.Password,
	})
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	} else {
		dto.Success(c, nil)
	}

}

func (a Api) Login(c *gin.Context) {
	req := new(dto.User)
	err := c.ShouldBind(&req)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}

	auth, err := a.userService.Login(c, req)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	} else {
		dto.Success(c, auth)
	}

}

func (a Api) Profile(c *gin.Context) {
	user, err := a.userService.Profile(c)
	if err != nil {
		dto.Fail(c, http.StatusUnauthorized, err.Error())
		return
	} else {
		dto.Success(c, user)
	}
}

func (a Api) UpdateProfile(c *gin.Context) {
	var user = model.User{}
	err := c.ShouldBind(&user)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}

	err = a.userService.Update(c, &model.User{Name: user.Name, Username: user.Username, Email: user.Email})
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}
	dto.Success(c, nil)
}

func (a Api) UpdatePassword(c *gin.Context) {
	var passwd dto.ChangePassword
	err := c.ShouldBind(&passwd)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}

	_user := c.MustGet("user").(*model.User)
	if _user.Password == "" {
		hashpass, err := utils.HashPassword(passwd.NewPassword)
		if err != nil {
			dto.Fail(c, http.StatusInternalServerError, err.Error())
			return
		}
		_user.Password = hashpass
	} else {
		if !utils.CheckPassword(_user.Password, passwd.Password) {
			dto.Fail(c, http.StatusBadRequest, "password not match")
			return
		}
		hashpass, err := utils.HashPassword(passwd.NewPassword)
		if err != nil {
			dto.Fail(c, http.StatusInternalServerError, err.Error())
			return
		}
		_user.Password = hashpass
	}
	err = a.userService.Update(c, _user)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}
	dto.Success(c, nil)
}

func (a Api) ListUser(c *gin.Context) {
	limit, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	offset := (page - 1) * limit
	active := c.QueryArray("active[]")
	if !slice.ContainSubSlice([]string{"true", "false", ""}, active) {
		dto.Fail(c, http.StatusBadRequest, "active must be true or false")
		return
	}

	users, total, err := a.userService.List(c, limit, offset, active)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}
	dto.Success(c, gin.H{
		"users": users,
		"total": total,
	})
}

func (a Api) CreateUser(c *gin.Context) {
	var user model.User
	err := c.ShouldBind(&user)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}
	fmt.Printf("user:%+v\n", user)
	err = a.userService.Create(c, &user)
	if err != nil {
		dto.Fail(c, http.StatusInternalServerError, err.Error())
		return
	}

	dto.Success(c, nil)
}

func (a Api) GetUser(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
	user, err := a.userService.GetByID(c, id)
	if err != nil {
		dto.Fail(c, 500, err.Error())
		return
	}
	dto.Success(c, user)
}

func (a Api) EditUser(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
	var user model.User
	err := c.ShouldBind(&user)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}

	user.ID = int64(id)
	err = a.userService.Update(c, &user)
	if err != nil {
		dto.Fail(c, 500, err.Error())
		return
	}
	dto.Success(c, nil)
}

func (a Api) DeleteUser(c *gin.Context) {
	id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
	err := a.userService.Delete(c, id)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}
	dto.Success(c, nil)
}

func (a Api) UserOption(c *gin.Context) {
	option := strings.ToLower(c.Param("option"))
	var batchid dto.BatchIDRequest
	err := c.ShouldBind(&batchid)
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}
	switch option {
	case "enable":
		err = a.userService.BatchEnable(c, batchid.IDs)
	case "disable":
		err = a.userService.BatchDisable(c, batchid.IDs)
	case "delete":
		err = a.userService.BatchDelete(c, batchid.IDs)
	default:
		dto.Fail(c, 400, "invalid option, only support enable, disable, delete")
		return
	}
	if err != nil {
		dto.Fail(c, 400, err.Error())
		return
	}
	dto.Success(c, nil)

}
