package controllers

import (
	"net/http"
	"strconv"
	"strings"

	"nearle/models"
	"nearle/services"

	"github.com/gofiber/fiber/v2"
)

type UserController struct {
	userService services.UserService
}

func NewUserController(userService services.UserService) *UserController {
	return &UserController{userService: userService}
}

func (ctl *UserController) GetAllUsers(c *fiber.Ctx) error {
	roleID, _ := strconv.Atoi(c.Query("roleid", "0"))
	tenantID, _ := strconv.Atoi(c.Query("tenantid", "0"))
	pageno, _ := strconv.Atoi(c.Query("pageno", "1"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize", "10"))
	keyword := c.Query("keyword", "")

	if tenantID == 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "tenantid is required",
			"status":  false,
		})
	}

	users, err := ctl.userService.GetAllUsers(roleID, tenantID, pageno, pagesize, keyword)
	if err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": users,
	})
}

func (ctl *UserController) GetUserInfo(c *fiber.Ctx) error {
	uid, err := strconv.Atoi(c.Query("userid"))
	if err != nil || uid <= 0 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid userid",
			"status":  false,
		})
	}

	user, err := ctl.userService.GetUserByID(uid)
	if err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": user,
	})
}

func (ctl *UserController) Login(c *fiber.Ctx) error {
	var user models.User
	if err := c.BodyParser(&user); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	info, err := ctl.userService.Login(user)
	if err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": "User not found",
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": info,
	})
}

func (ctl *UserController) TenantLogin(c *fiber.Ctx) error {
	var user models.User
	if err := c.BodyParser(&user); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
		})
	}

	info, err := ctl.userService.TenantLogin(user)
	if err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": err.Error(),
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": info,
	})
}

func (ctl *UserController) UpdateStaff(c *fiber.Ctx) error {
	var user models.User
	if err := c.BodyParser(&user); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
		})
	}

	// This endpoint also doubles as the password-setup/reset call (userid +
	// password only, everything else left zero so GORM's Updates skips it) —
	// guard the one field that has no validation anywhere else on this path.
	if pw := strings.TrimSpace(user.Password); pw != "" && len(pw) < 6 {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusBadRequest,
			"message": "Password must be at least 6 characters",
		})
	}

	if err := ctl.userService.UpdateStaff(user); err != nil {
		return c.JSON(fiber.Map{
			"status":  false,
			"code":    http.StatusConflict,
			"message": err.Error(),
		})
	}

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusAccepted,
		"message": "User update successful",
	})
}

func (ctl *UserController) AppLogin(c *fiber.Ctx) error {
	var user models.User

	if err := c.BodyParser(&user); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    400,
			"status":  false,
			"message": "Invalid request body",
		})
	}

	_, resp, err := ctl.userService.AppLogin(user)
	if err != nil {
		// Use resp.Code if present, fallback to 409
		code := http.StatusConflict
		if v, ok := resp["code"].(int); ok {
			code = v
		}
		return c.Status(code).JSON(resp)
	}

	// ✅ Always return resp
	return c.Status(http.StatusOK).JSON(resp)
}

func (ctl *UserController) CreateUser(c *fiber.Ctx) error {
	var user models.User

	// Parse request body
	if err := c.BodyParser(&user); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"status":  false,
			"message": "Invalid request body",
		})
	}

	// Call service
	info, err := ctl.userService.CreateUser(user)
	if err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"code":    http.StatusConflict,
			"status":  false,
			"message": "Failed",
		})
	}

	return c.Status(http.StatusCreated).JSON(fiber.Map{
		"code":    http.StatusCreated,
		"status":  true,
		"message": "Success",
		"details": info,
	})
}

func (ctl *UserController) TenantWebLogin(c *fiber.Ctx) error {
	var user models.User
	if err := c.BodyParser(&user); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"status":  false,
			"code":    fiber.StatusBadRequest,
			"message": "Invalid request body",
		})
	}

	info, resp := ctl.userService.TenantWebLogin(user)

	// Ensure the response map contains the correct status code
	code, ok := resp["code"].(int)
	if !ok {
		code = fiber.StatusInternalServerError
	}

	// Include tenant user info if login successful (code 200)
	if code == fiber.StatusOK {
		resp["details"] = info
	}

	return c.Status(code).JSON(resp)
}

func (ctl *UserController) DeleteUser(c *fiber.Ctx) error {
	uid, err := strconv.Atoi(c.Query("userid"))
	if err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid user ID",
			"status":  false,
		})
	}

	if err := ctl.userService.DeleteUser(uid); err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "User successfully deleted",
		"status":  true,
	})
}

