package handlers

import (
	"strconv"
	"time"

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

type UpdateWalletActiveReq struct {
	IsActive bool `json:"is_active" validate:"required" example:"true"`
}
type WalletRes struct {
	ID             int64     `json:"id" example:"1"`
	Balance        float32   `json:"amount" example:"100.0"`
	IsWithdraw     bool      `json:"is_withdraw" example:"true"`
	IsBettable     bool      `json:"is_bettable" example:"true"`
	IsTransferable bool      `json:"is_transferable" example:"true"`
	IsActive       bool      `json:"is_active" example:"true"`
	UserID         int64     `json:"user_id" example:"1"`
	UpdatedAt      time.Time `json:"updated_at"`
	CreatedAt      time.Time `json:"created_at"`
}

func convertWallet(wallet domain.Wallet) WalletRes {
	return WalletRes{
		ID:             wallet.ID,
		Balance:        wallet.Balance.Float32(),
		IsWithdraw:     wallet.IsWithdraw,
		IsBettable:     wallet.IsBettable,
		IsTransferable: wallet.IsTransferable,
		IsActive:       wallet.IsActive,
		UserID:         wallet.UserID,
		UpdatedAt:      wallet.UpdatedAt,
		CreatedAt:      wallet.CreatedAt,
	}
}

type CustomerWalletRes struct {
	ID               int64     `json:"id" example:"1"`
	RegularID        int64     `json:"regular_id" example:"1"`
	RegularBalance   float32   `json:"regular_balance" example:"100.0"`
	StaticID         int64     `json:"static_id" example:"1"`
	StaticBalance    float32   `json:"static_balance" example:"100.0"`
	CustomerID       int64     `json:"customer_id" example:"1"`
	RegularUpdatedAt time.Time `json:"regular_updated_at"`
	StaticUpdatedAt  time.Time `json:"static_updated_at"`
	CreatedAt        time.Time `json:"created_at"`
}

func ConvertCustomerWallet(wallet domain.GetCustomerWallet) CustomerWalletRes {
	return CustomerWalletRes{
		ID:               wallet.ID,
		RegularID:        wallet.RegularID,
		RegularBalance:   wallet.RegularBalance.Float32(),
		StaticID:         wallet.StaticID,
		StaticBalance:    wallet.StaticBalance.Float32(),
		CustomerID:       wallet.CustomerID,
		RegularUpdatedAt: wallet.RegularUpdatedAt,
		StaticUpdatedAt:  wallet.StaticUpdatedAt,
		CreatedAt:        wallet.CreatedAt,
	}
}

type BranchWalletRes struct {
	ID              int64     `json:"id" example:"1"`
	Balance         float32   `json:"balance" example:"100.0"`
	IsActive        bool      `json:"is_active" example:"true"`
	Name            string    `json:"name" example:"true"`
	Location        string    `json:"location" example:"somewhere"`
	BranchManagerID int64     `json:"branch_manager_id" example:"1"`
	CompanyID       int64     `json:"company_id" example:"1"`
	IsSelfOwned     bool      `json:"is_self_owned" example:"false"`
	UpdatedAt       time.Time `json:"updated_at"`
	CreatedAt       time.Time `json:"created_at"`
}

// GetWalletByID godoc
// @Summary Get wallet by ID
// @Description Retrieve wallet details by wallet ID
// @Tags wallet
// @Accept json
// @Produce json
// @Param id path int true "Wallet ID"
// @Success 200 {object} WalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /wallet/{id} [get]
func (h *Handler) GetWalletByID(c *fiber.Ctx) error {
	walletID := c.Params("id")
	id, err := strconv.ParseInt(walletID, 10, 64)
	if err != nil {
		h.logger.Error("Invalid wallet ID", "walletID", walletID, "error", err)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID")
	}

	wallet, err := h.walletSvc.GetWalletByID(c.Context(), id)
	if err != nil {
		h.logger.Error("Failed to get wallet by ID", "walletID", id, "error", err)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallet")
	}

	res := convertWallet(wallet)

	return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil)
}

// GetAllWallets godoc
// @Summary Get all wallets
// @Description Retrieve all wallets
// @Tags wallet
// @Accept json
// @Produce json
// @Success 200 {array} WalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /wallet [get]
func (h *Handler) GetAllWallets(c *fiber.Ctx) error {

	wallets, err := h.walletSvc.GetAllWallets(c.Context())

	if err != nil {
		h.logger.Error("Failed to get wallets", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil)
	}

	var res []WalletRes = make([]WalletRes, 0, len(wallets))

	for _, wallet := range wallets {
		res = append(res, convertWallet(wallet))
	}

	return response.WriteJSON(c, fiber.StatusOK, "All wallets retrieved successfully", res, nil)

}

// GetAllBranchWallets godoc
// @Summary Get all branch wallets
// @Description Retrieve all branch wallets
// @Tags wallet
// @Accept json
// @Produce json
// @Success 200 {array} WalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /branchWallet [get]
func (h *Handler) GetAllBranchWallets(c *fiber.Ctx) error {

	wallets, err := h.walletSvc.GetAllBranchWallets(c.Context())

	if err != nil {
		h.logger.Error("Failed to get wallets", "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil)
	}

	var res []BranchWalletRes = make([]BranchWalletRes, 0, len(wallets))

	for _, wallet := range wallets {
		res = append(res, BranchWalletRes{
			ID:              wallet.ID,
			Balance:         wallet.Balance.Float32(),
			IsActive:        wallet.IsActive,
			Name:            wallet.Name,
			Location:        wallet.Location,
			BranchManagerID: wallet.BranchManagerID,
			CompanyID:       wallet.CompanyID,
			IsSelfOwned:     wallet.IsSelfOwned,
			UpdatedAt:       wallet.UpdatedAt,
			CreatedAt:       wallet.CreatedAt,
		})
	}

	return response.WriteJSON(c, fiber.StatusOK, "All Wallets retrieved", res, nil)

}

// UpdateWalletActive godoc
// @Summary Activate and Deactivate Wallet
// @Description Can activate and deactivate wallet
// @Tags wallet
// @Accept json
// @Produce json
// @Param id path int true "Wallet ID"
// @Param updateCashOut body UpdateWalletActiveReq true "Update Wallet Active"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /wallet/{id} [patch]
func (h *Handler) UpdateWalletActive(c *fiber.Ctx) error {

	walletID := c.Params("id")
	id, err := strconv.ParseInt(walletID, 10, 64)
	if err != nil {
		h.logger.Error("Invalid wallet ID", "walletID", walletID, "error", err)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID")
	}

	var req UpdateWalletActiveReq
	if err := c.BodyParser(&req); err != nil {
		h.logger.Error("Failed to parse UpdateWalletActive request", "error", err)
		return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
	}

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

	err = h.walletSvc.UpdateWalletActive(c.Context(), id, req.IsActive)
	if err != nil {
		h.logger.Error("Failed to update wallet active status", "walletID", id, "error", err)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to update wallet")
	}

	return response.WriteJSON(c, fiber.StatusOK, "Wallet successfully updated", nil, nil)
}

// GetCustomerWallet godoc
// @Summary Get customer wallet
// @Description Retrieve customer wallet details
// @Tags wallet
// @Accept json
// @Produce json
// @Param company_id header int true "Company ID"
// @Security Bearer
// @Success 200 {object} CustomerWalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /user/wallet [get]
func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error {

	userID, ok := c.Locals("user_id").(int64)
	if !ok || userID == 0 {
		h.logger.Error("Invalid user ID in context")
		return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
	}

	role, ok := c.Locals("role").(domain.Role)
	if !ok {
		h.logger.Error("Invalid role in context", "userID", userID)
		return fiber.NewError(fiber.StatusUnauthorized, "Invalid role")
	}

	if role != domain.RoleCustomer {
		h.logger.Error("Unauthorized access", "userID", userID, "role", role)
		return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized access")
	}

	// companyID, err := strconv.ParseInt(c.Get("company_id"), 10, 64)
	// if err != nil {
	// 	h.logger.Error("Invalid company_id header", "value", c.Get("company_id"), "error", err)
	// 	return fiber.NewError(fiber.StatusBadRequest, "Invalid company_id")
	// }

	// h.logger.Info("Fetching customer wallet", "userID", userID)

	wallet, err := h.walletSvc.GetWalletsByUser(c.Context(), userID)
	if err != nil {
		h.logger.Error("Failed to get customer wallet", "userID", userID, "error", err)
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallet")
	}

	res := convertWallet(wallet[0])

	return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil)
}

// GetWalletForCashier godoc
// @Summary Get wallet for cashier
// @Description Get wallet for cashier
// @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 /cashierWallet [get]
func (h *Handler) GetWalletForCashier(c *fiber.Ctx) error {
	cashierID, ok := c.Locals("user_id").(int64)

	if !ok || cashierID == 0 {
		h.logger.Error("Invalid cashier ID in context")
		return response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid cashier identification", nil, nil)
	}

	role, ok := c.Locals("role").(domain.Role)

	if !ok || role != domain.RoleCashier {
		h.logger.Error("Unauthorized access", "cashierID", cashierID, "role", role)
		return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
	}

	branchID, ok := c.Locals("branch_id").(domain.ValidInt64)
	if !ok || !branchID.Valid {
		h.logger.Error("Invalid branch ID in context", "cashierID", cashierID)
		return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", nil, nil)
	}

	branch, err := h.branchSvc.GetBranchByID(c.Context(), branchID.Value)

	if err != nil {
		h.logger.Error("Failed to get branch by ID", "branchID", branchID.Value, "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil)
	}

	wallet, err := h.walletSvc.GetWalletByID(c.Context(), branch.WalletID)

	if err != nil {
		h.logger.Error("Failed to get wallet for cashier", "cashierID", cashierID, "error", err)
		return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallet", err, nil)
	}

	res := WalletRes{
		ID:             wallet.ID,
		Balance:        wallet.Balance.Float32(),
		IsWithdraw:     wallet.IsWithdraw,
		IsBettable:     wallet.IsBettable,
		IsTransferable: wallet.IsTransferable,
		IsActive:       wallet.IsActive,
		UserID:         wallet.UserID,
		UpdatedAt:      wallet.UpdatedAt,
		CreatedAt:      wallet.CreatedAt,
	}
	return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil)
}
