package handlers

import (
	"fmt"
	"strconv"
	"time"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
	"github.com/gofiber/fiber/v2"
)

type CreateCashierReq struct {
	FirstName   string `json:"first_name" example:"John"`
	LastName    string `json:"last_name" example:"Doe"`
	Email       string `json:"email" example:"john.doe@example.com"`
	PhoneNumber string `json:"phone_number" example:"1234567890"`
	Password    string `json:"password" example:"password123"`
	BranchID    int64  `json:"branch_id" example:"1"`
	Suspended   bool   `json:"suspended" example:"false"`
}

// CreateCashier godoc
// @Summary Create cashier
// @Description Create cashier
// @Tags cashier
// @Accept json
// @Produce json
// @Param cashier body CreateCashierReq true "Create cashier"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /cashiers [post]
func (h *Handler) CreateCashier(c *fiber.Ctx) error {

	// Get user_id from middleware
	// companyID := c.Locals("company_id").(domain.ValidInt64)

	var req CreateCashierReq
	if err := c.BodyParser(&req); err != nil {
		h.logger.Error("RegisterUser failed", "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
	}
	valErrs, ok := h.validator.Validate(c, req)
	if !ok {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
	}

	// Cashiers inherit the company id from the branch id
	branch, err := h.branchSvc.GetBranchByID(c.Context(), req.BranchID)

	if err != nil {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID is invalid", nil, nil)
	}
	userRequest := domain.CreateUserReq{
		FirstName:   req.FirstName,
		LastName:    req.LastName,
		Email:       req.Email,
		PhoneNumber: req.PhoneNumber,
		Password:    req.Password,
		Role:        string(domain.RoleCashier),
		Suspended:   req.Suspended,
		CompanyID: domain.ValidInt64{
			Value: branch.CompanyID,
			Valid: true,
		},
	}
	fmt.Print(req.Suspended)
	newUser, err := h.userSvc.CreateUser(c.Context(), userRequest, true)
	if err != nil {
		h.logger.Error("CreateCashier failed", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil)
	}

	err = h.branchSvc.CreateBranchCashier(c.Context(), req.BranchID, newUser.ID)
	if err != nil {
		h.logger.Error("CreateCashier failed", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create cashier", nil, nil)
	}
	return response.WriteJSON(c, fiber.StatusOK, "Cashier created successfully", nil, nil)

}

type GetCashierRes struct {
	ID             int64       `json:"id"`
	FirstName      string      `json:"first_name"`
	LastName       string      `json:"last_name"`
	Email          string      `json:"email"`
	PhoneNumber    string      `json:"phone_number"`
	Role           domain.Role `json:"role"`
	EmailVerified  bool        `json:"email_verified"`
	PhoneVerified  bool        `json:"phone_verified"`
	CreatedAt      time.Time   `json:"created_at"`
	UpdatedAt      time.Time   `json:"updated_at"`
	SuspendedAt    time.Time   `json:"suspended_at"`
	Suspended      bool        `json:"suspended"`
	LastLogin      time.Time   `json:"last_login"`
	BranchID       int64       `json:"branch_id"`
	BranchName     string      `json:"branch_name"`
	BranchWallet   int64       `json:"branch_wallet"`
	BranchLocation string      `json:"branch_location"`
}

// GetAllCashiers godoc
// @Summary Get all cashiers
// @Description Get all cashiers
// @Tags cashier
// @Accept json
// @Produce json
// @Param page query int false "Page number"
// @Param page_size query int false "Page size"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /cashiers [get]
func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
	role := c.Locals("role").(domain.Role)
	companyId := c.Locals("company_id").(domain.ValidInt64)

	if role != domain.RoleSuperAdmin && !companyId.Valid {
		return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
	}
	filter := user.Filter{
		Role:      string(domain.RoleCashier),
		CompanyID: companyId,
		Page: domain.ValidInt{
			Value: c.QueryInt("page", 1) - 1,
			Valid: true,
		},
		PageSize: domain.ValidInt{
			Value: c.QueryInt("page_size", 10),
			Valid: true,
		},
	}

	valErrs, ok := h.validator.Validate(c, filter)
	if !ok {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
	}

	cashiers, total, err := h.userSvc.GetAllCashiers(c.Context())
	if err != nil {
		h.logger.Error("GetAllCashiers failed", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
	}

	var result []GetCashierRes = make([]GetCashierRes, 0, len(cashiers))

	for _, cashier := range cashiers {
		lastLogin, err := h.authSvc.GetLastLogin(c.Context(), cashier.ID)
		if err != nil {
			if err == authentication.ErrRefreshTokenNotFound {
				lastLogin = &cashier.CreatedAt
			} else {
				h.logger.Error("Failed to get user last login", "userID", cashier.ID, "error", err)
				return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
			}
		}

		result = append(result, GetCashierRes{
			ID:             cashier.ID,
			FirstName:      cashier.FirstName,
			LastName:       cashier.LastName,
			Email:          cashier.Email,
			PhoneNumber:    cashier.PhoneNumber,
			Role:           cashier.Role,
			EmailVerified:  cashier.EmailVerified,
			PhoneVerified:  cashier.PhoneVerified,
			CreatedAt:      cashier.CreatedAt,
			UpdatedAt:      cashier.UpdatedAt,
			SuspendedAt:    cashier.SuspendedAt,
			Suspended:      cashier.Suspended,
			LastLogin:      *lastLogin,
			BranchID:       cashier.BranchID,
			BranchName:     cashier.BranchName,
			BranchWallet:   cashier.BranchWallet,
			BranchLocation: cashier.BranchLocation,
		})
	}

	return response.WritePaginatedJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", result, nil, filter.Page.Value, int(total))

}

// GetCashierByID godoc
// @Summary Get cashier by id
// @Description Get a single cashier by id
// @Tags cashier
// @Accept json
// @Produce json
// @Param id path int true "User ID"
// @Success 200 {object} UserProfileRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /cashier/{id} [get]
func (h *Handler) GetCashierByID(c *fiber.Ctx) error {
	// branchId := int64(12) //c.Locals("branch_id").(int64)
	// filter := user.Filter{
	// 	Role: string(domain.RoleUser),
	// 	BranchId: user.ValidBranchId{
	// 		Value: branchId,
	// 		Valid: true,
	// 	},
	// 	Page:     c.QueryInt("page", 1),
	// 	PageSize: c.QueryInt("page_size", 10),
	// }
	// valErrs, ok := validator.Validate(c, filter)
	// if !ok {
	// 	return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
	// }

	stringID := c.Params("id")
	cashierID, err := strconv.ParseInt(stringID, 10, 64)
	if err != nil {
		h.logger.Error("failed to fetch user using UserID", "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil)
	}

	user, err := h.userSvc.GetCashierByID(c.Context(), cashierID)

	if err != nil {
		h.logger.Error("Get User By ID failed", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
	}

	lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
	if err != nil {
		if err != authentication.ErrRefreshTokenNotFound {
			h.logger.Error("Failed to get user last login", "cashierID", user.ID, "error", err)
			return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
		}
		lastLogin = &user.CreatedAt
	}

	res := GetCashierRes{
		ID:             user.ID,
		FirstName:      user.FirstName,
		LastName:       user.LastName,
		Email:          user.Email,
		PhoneNumber:    user.PhoneNumber,
		Role:           user.Role,
		EmailVerified:  user.EmailVerified,
		PhoneVerified:  user.PhoneVerified,
		CreatedAt:      user.CreatedAt,
		UpdatedAt:      user.UpdatedAt,
		SuspendedAt:    user.SuspendedAt,
		Suspended:      user.Suspended,
		LastLogin:      *lastLogin,
		BranchID:       user.BranchID,
		BranchName:     user.BranchName,
		BranchWallet:   user.BranchWallet,
		BranchLocation: user.BranchLocation,
	}
	return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
}

type updateCashierReq struct {
	FirstName string `json:"first_name" example:"John"`
	LastName  string `json:"last_name" example:"Doe"`
	Suspended bool   `json:"suspended" example:"false"`
}

// UpdateCashier godoc
// @Summary Update cashier
// @Description Update cashier
// @Tags cashier
// @Accept json
// @Produce json
// @Param id path int true "Cashier ID"
// @Param cashier body updateCashierReq true "Update cashier"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /cashiers/{id} [put]
func (h *Handler) UpdateCashier(c *fiber.Ctx) error {
	cashierIdStr := c.Params("id")
	cashierId, err := strconv.ParseInt(cashierIdStr, 10, 64)
	if err != nil {
		h.logger.Error("UpdateCashier failed", "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil)
	}
	var req updateCashierReq
	if err := c.BodyParser(&req); err != nil {
		h.logger.Error("UpdateCashier failed", "error", err)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
	}

	valErrs, ok := h.validator.Validate(c, req)

	if !ok {
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
	}

	err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
		UserId: cashierId,
		FirstName: domain.ValidString{
			Value: req.FirstName,
			Valid: req.FirstName != "",
		},
		LastName: domain.ValidString{
			Value: req.LastName,
			Valid: req.LastName != "",
		},
		Suspended: domain.ValidBool{
			Value: req.Suspended,
			Valid: true,
		},
	},
	)
	if err != nil {
		h.logger.Error("UpdateCashier failed", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update cashier", nil, nil)
	}
	return response.WriteJSON(c, fiber.StatusOK, "Cashier updated successfully", nil, nil)

}
