package handlers

import (
	"encoding/json"
	"fmt"
	"hamster-tycoon/storage/dao"
	"hamster-tycoon/storage/model"
	"hamster-tycoon/storage/validators"
	"hamster-tycoon/utils"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"google.golang.org/api/oauth2/v2"
)

func (hc *handlersContext) getAllUsers(c *gin.Context) {
	users, err := hc.db.GetAllUsers()
	if err != nil {
		utils.GetLoggerFromCtx(c).WithError(err).Error("error while getting users")
		utils.JSONErrorWithMessage(c.Writer, model.ErrInternalServer, "Error while getting users")
		return
	}
	utils.JSON(c.Writer, http.StatusOK, users)
}

func (hc *handlersContext) connectUser(c *gin.Context) {
	authorizationHeader := c.GetHeader("Authorization")
	authorizationHeaderSplitted := strings.Split(authorizationHeader, " ")
	if len(authorizationHeaderSplitted) != 2 {
		utils.JSONError(c.Writer, model.ErrBadRequestFormat)
		return
	}

	oauth2Service, err := oauth2.New(&http.Client{})
	if oauth2Service == nil {
		fmt.Println(err)
		utils.JSONError(c.Writer, model.ErrInternalServer)
		return
	}
	tokenInfoCall := oauth2Service.Tokeninfo()
	tokenInfoCall.IdToken(authorizationHeaderSplitted[1])
	tokenInfo, err := tokenInfoCall.Do()
	if err != nil {
		utils.GetLogger().WithError(err).Error(err)
		utils.JSONError(c.Writer, model.ErrBadRequestFormat)
		return
	}
	user, err := hc.userService.GetUserFromGoogleID(tokenInfo.UserId)
	if err != nil {
		utils.GetLogger().WithError(err).Error(err)
		if castedError, ok := err.(*model.APIError); ok {
			if castedError.Type == model.ErrNotFound.Type {
				user, err := hc.userService.CreateUserFromGoogleToken(tokenInfo.UserId, tokenInfo.Email)
				if err != nil {
					fmt.Println(err)
					utils.JSONError(c.Writer, model.ErrInternalServer)
					return
				}
				utils.JSON(c.Writer, 200, user)
				return
			}
			utils.JSONError(c.Writer, *castedError)
			return
		}
		utils.JSONError(c.Writer, model.ErrInternalServer)
		return
	}
	fmt.Println("Found the user " + user.Nickname)
	fmt.Println("Return 200")
	utils.JSON(c.Writer, 200, user)
}

func (hc *handlersContext) createUser(c *gin.Context) {
	b, err := c.GetRawData()
	if err != nil {
		utils.GetLoggerFromCtx(c).WithError(err).Error("error while creating user, read data fail")
		utils.JSONError(c.Writer, model.ErrInternalServer)
		return
	}

	userToCreate := model.UserEditable{}
	err = json.Unmarshal(b, &userToCreate)
	if err != nil {
		utils.JSONError(c.Writer, model.ErrBadRequestFormat)
		return
	}

	err = hc.validator.StructCtx(c, userToCreate)
	if err != nil {
		utils.JSONError(c.Writer, validators.NewDataValidationAPIError(err))
		return
	}

	user := model.User{
		UserEditable: userToCreate,
	}

	err = hc.db.CreateUser(&user)
	if e, ok := err.(*dao.Error); ok {
		switch {
		case e.Type == dao.ErrTypeDuplicate:
			utils.JSONErrorWithMessage(c.Writer, model.ErrAlreadyExists, "User already exists")
			return
		default:
			utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("error CreateUser: Error type not handled")
			utils.JSONError(c.Writer, model.ErrInternalServer)
			return
		}
	} else if err != nil {
		utils.GetLoggerFromCtx(c).WithError(err).Error("error while creating user")
		utils.JSONError(c.Writer, model.ErrInternalServer)
		return
	}

	utils.JSON(c.Writer, http.StatusCreated, user)
}

func (hc *handlersContext) getUser(c *gin.Context) {
	userID := c.Param("id")

	err := hc.validator.VarCtx(c, userID, "uuid4")
	if err != nil {
		utils.JSONError(c.Writer, validators.NewDataValidationAPIError(err))
		return
	}

	user, err := hc.db.GetUsersByID(userID)
	if e, ok := err.(*dao.Error); ok {
		switch {
		case e.Type == dao.ErrTypeNotFound:
			utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User not found")
			return
		default:
			utils.GetLoggerFromCtx(c).WithError(err).WithField("type", e.Type).Error("error GetUser: get user error type not handled")
			utils.JSONError(c.Writer, model.ErrInternalServer)
			return
		}
	} else if err != nil {
		utils.GetLoggerFromCtx(c).WithError(err).Error("error while get user")
		utils.JSONError(c.Writer, model.ErrInternalServer)
		return
	}

	if user == nil {
		utils.JSONErrorWithMessage(c.Writer, model.ErrNotFound, "User not found")
		return
	}

	utils.JSON(c.Writer, http.StatusOK, user)
}
