package handler

import (
	"log/slog"
	"net/http"

	"github.com/denisovdennis/autohero/internal/model"
	"github.com/denisovdennis/autohero/internal/storage"
)

// AchievementHandler serves achievement API endpoints.
type AchievementHandler struct {
	achievementStore *storage.AchievementStore
	heroStore        *storage.HeroStore
	logger           *slog.Logger
}

// NewAchievementHandler creates a new AchievementHandler.
func NewAchievementHandler(achievementStore *storage.AchievementStore, heroStore *storage.HeroStore, logger *slog.Logger) *AchievementHandler {
	return &AchievementHandler{
		achievementStore: achievementStore,
		heroStore:        heroStore,
		logger:           logger,
	}
}

// GetHeroAchievements returns all achievements with unlocked status for the hero.
// GET /api/v1/hero/achievements
func (h *AchievementHandler) GetHeroAchievements(w http.ResponseWriter, r *http.Request) {
	telegramID, ok := resolveTelegramID(r)
	if !ok {
		writeJSON(w, http.StatusBadRequest, map[string]string{
			"error": "missing telegramId",
		})
		return
	}

	hero, err := h.heroStore.GetByTelegramID(r.Context(), telegramID)
	if err != nil {
		h.logger.Error("failed to get hero for achievements", "error", err)
		writeJSON(w, http.StatusInternalServerError, map[string]string{
			"error": "failed to load hero",
		})
		return
	}
	if hero == nil {
		writeJSON(w, http.StatusNotFound, map[string]string{
			"error": "hero not found",
		})
		return
	}

	// Load all achievement definitions.
	allAchievements, err := h.achievementStore.ListAchievements(r.Context())
	if err != nil {
		h.logger.Error("failed to list achievements", "error", err)
		writeJSON(w, http.StatusInternalServerError, map[string]string{
			"error": "failed to load achievements",
		})
		return
	}

	// Load hero's unlocked achievements.
	heroAchievements, err := h.achievementStore.GetHeroAchievements(r.Context(), hero.ID)
	if err != nil {
		h.logger.Error("failed to get hero achievements", "hero_id", hero.ID, "error", err)
		writeJSON(w, http.StatusInternalServerError, map[string]string{
			"error": "failed to load hero achievements",
		})
		return
	}

	// Build lookup of unlocked achievement IDs.
	unlockedMap := make(map[string]*model.HeroAchievement, len(heroAchievements))
	for i := range heroAchievements {
		unlockedMap[heroAchievements[i].AchievementID] = &heroAchievements[i]
	}

	// Build response combining definitions with unlock status.
	views := make([]model.AchievementView, 0, len(allAchievements))
	for _, a := range allAchievements {
		view := model.AchievementView{
			Achievement: a,
		}
		if ha, ok := unlockedMap[a.ID]; ok {
			view.Unlocked = true
			view.UnlockedAt = &ha.UnlockedAt
		}
		views = append(views, view)
	}

	writeJSON(w, http.StatusOK, views)
}
