package economy

import (
	"encoding/json"
	"errors"
	"net/http"

	"hakemsho/internal/auth"
	"hakemsho/internal/httpx"
)

// Handler endpointهای فروشگاه و کیف‌پول (همه پشت JWT).
type Handler struct {
	svc *Service
}

func NewHandler(svc *Service) *Handler { return &Handler{svc: svc} }

func uid(r *http.Request) (int64, bool) { return auth.UserID(r.Context()) }

// Wallet — GET /api/wallet
func (h *Handler) Wallet(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	p, err := h.svc.GetProfile(r.Context(), id)
	if err != nil {
		httpx.Error(w, http.StatusNotFound, "user not found")
		return
	}
	httpx.JSON(w, http.StatusOK, p)
}

// Shop — GET /api/shop
func (h *Handler) Shop(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	owned, err := h.svc.OwnedCards(r.Context(), id)
	if err != nil {
		httpx.Error(w, http.StatusInternalServerError, "server error")
		return
	}
	p, _ := h.svc.GetProfile(r.Context(), id)
	selected := "simple"
	if p != nil {
		selected = p.SelectedCard
	}
	httpx.JSON(w, http.StatusOK, map[string]any{
		"catalog":       h.svc.Catalog(),
		"owned_cards":   owned,
		"selected_card": selected,
	})
}

type cardReq struct {
	CardID string `json:"card_id"`
}

// BuyCard — POST /api/shop/buy-card
func (h *Handler) BuyCard(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	var req cardReq
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httpx.Error(w, http.StatusBadRequest, "invalid body")
		return
	}
	switch err := h.svc.BuyCard(r.Context(), id, req.CardID); {
	case err == nil:
		httpx.JSON(w, http.StatusOK, map[string]string{"message": "ok"})
	case errors.Is(err, ErrNotFound):
		httpx.Error(w, http.StatusNotFound, "card not found")
	case errors.Is(err, ErrAlreadyOwned):
		httpx.Error(w, http.StatusConflict, "already owned")
	case errors.Is(err, ErrInsufficient):
		httpx.Error(w, http.StatusPaymentRequired, "insufficient coins")
	default:
		httpx.Error(w, http.StatusInternalServerError, "server error")
	}
}

// SelectCard — POST /api/shop/select-card
func (h *Handler) SelectCard(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	var req cardReq
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httpx.Error(w, http.StatusBadRequest, "invalid body")
		return
	}
	switch err := h.svc.SelectCard(r.Context(), id, req.CardID); {
	case err == nil:
		httpx.JSON(w, http.StatusOK, map[string]string{"message": "ok"})
	case errors.Is(err, ErrNotFound):
		httpx.Error(w, http.StatusNotFound, "card not found")
	case errors.Is(err, ErrNotOwned):
		httpx.Error(w, http.StatusForbidden, "card not owned")
	default:
		httpx.Error(w, http.StatusInternalServerError, "server error")
	}
}

// Purchase — POST /api/shop/purchase (تأیید خرید IAP)
func (h *Handler) Purchase(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	var req PurchaseRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httpx.Error(w, http.StatusBadRequest, "invalid body")
		return
	}
	switch err := h.svc.VerifyPurchase(r.Context(), id, req); {
	case err == nil:
		p, _ := h.svc.GetProfile(r.Context(), id)
		httpx.JSON(w, http.StatusOK, map[string]any{"message": "ok", "wallet": p})
	case errors.Is(err, ErrAlreadyOwned):
		httpx.Error(w, http.StatusConflict, "already processed")
	case errors.Is(err, ErrIAPInvalid):
		httpx.Error(w, http.StatusBadRequest, "purchase not valid")
	case errors.Is(err, ErrNotFound):
		httpx.Error(w, http.StatusNotFound, "package not found")
	default:
		httpx.Error(w, http.StatusInternalServerError, "server error")
	}
}

// Stats — GET /api/stats (آمار پروفایل؛ نمایشِ کامل ویژه‌ی کاربران VIP)
func (h *Handler) Stats(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	p, err := h.svc.GetProfile(r.Context(), id)
	if err != nil {
		httpx.Error(w, http.StatusNotFound, "user not found")
		return
	}
	resp := map[string]any{"vip": p.VIP}
	if p.VIP {
		st, err := h.svc.GetStats(r.Context(), id)
		if err != nil {
			httpx.Error(w, http.StatusInternalServerError, "server error")
			return
		}
		resp["stats"] = st
	}
	httpx.JSON(w, http.StatusOK, resp)
}

// TablesInfo — GET /api/tables/info (باقیمانده‌ی میزهای خصوصیِ رایگان)
func (h *Handler) TablesInfo(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	remaining, unlimited := h.svc.PrivateTableInfo(r.Context(), id)
	httpx.JSON(w, http.StatusOK, map[string]any{
		"remaining": remaining,
		"unlimited": unlimited,
	})
}

// Leaderboard — GET /api/leaderboard (جدولِ رتبه‌بندیِ فصل)
func (h *Handler) Leaderboard(w http.ResponseWriter, r *http.Request) {
	if _, ok := uid(r); !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	list, err := h.svc.Leaderboard(r.Context(), 50)
	if err != nil {
		httpx.Error(w, http.StatusInternalServerError, "server error")
		return
	}
	httpx.JSON(w, http.StatusOK, map[string]any{
		"season":  h.svc.Season(r.Context()),
		"entries": list,
	})
}

// Daily — POST /api/rewards/daily
func (h *Handler) Daily(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	switch amount, err := h.svc.ClaimDaily(r.Context(), id); {
	case err == nil:
		httpx.JSON(w, http.StatusOK, map[string]any{"message": "ok", "amount": amount})
	case errors.Is(err, ErrTooSoon):
		httpx.Error(w, http.StatusTooManyRequests, "already claimed today")
	default:
		httpx.Error(w, http.StatusInternalServerError, "server error")
	}
}

type adReq struct {
	Token string `json:"token"`
}

// AdReward — POST /api/rewards/ad (سکه رایگان پس از دیدن کامل تبلیغ)
func (h *Handler) AdReward(w http.ResponseWriter, r *http.Request) {
	id, ok := uid(r)
	if !ok {
		httpx.Error(w, http.StatusUnauthorized, "unauthorized")
		return
	}
	var req adReq
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httpx.Error(w, http.StatusBadRequest, "invalid body")
		return
	}
	switch amount, err := h.svc.ClaimAdReward(r.Context(), id, req.Token); {
	case err == nil:
		httpx.JSON(w, http.StatusOK, map[string]any{"message": "ok", "amount": amount})
	case errors.Is(err, ErrAdNotVerified):
		httpx.Error(w, http.StatusBadRequest, "ad not verified")
	case errors.Is(err, ErrAdDuplicate):
		httpx.Error(w, http.StatusConflict, "already claimed")
	case errors.Is(err, ErrAdCap):
		httpx.Error(w, http.StatusTooManyRequests, "daily ad cap reached")
	default:
		httpx.Error(w, http.StatusInternalServerError, "server error")
	}
}
