package routes

import (
	"bssapp-backend/auth"
	"bssapp-backend/internal/auditlog"
	"bssapp-backend/permissions"
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/gorilla/mux"
)

/* =====================================================
   GET USER OVERRIDES
   GET /api/users/{id}/permissions
===================================================== */

func GetUserPermissionsHandler(db *sql.DB) http.HandlerFunc {

	return func(w http.ResponseWriter, r *http.Request) {

		// ✅ Auth kontrolü yeterli (Yetki middleware'de)
		claims, ok := auth.GetClaimsFromContext(r.Context())
		if !ok || claims == nil {
			http.Error(w, "unauthorized", http.StatusUnauthorized)
			return
		}

		idStr := mux.Vars(r)["id"]

		id, err := strconv.ParseInt(idStr, 10, 64)
		if err != nil || id <= 0 {
			http.Error(w, "invalid id", http.StatusBadRequest)
			return
		}

		repo := permissions.NewPermissionRepository(db)

		rows, err := repo.GetUserOverridesByUserID(id)
		if err != nil {
			http.Error(w, "db error", http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")

		json.NewEncoder(w).Encode(rows)
	}
}

/* =====================================================
   SAVE USER OVERRIDES
   POST /api/users/{id}/permissions
===================================================== */

func SaveUserPermissionsHandler(db *sql.DB) http.HandlerFunc {

	return func(w http.ResponseWriter, r *http.Request) {

		// ✅ Auth kontrolü yeterli
		claims, ok := auth.GetClaimsFromContext(r.Context())
		if !ok || claims == nil {
			http.Error(w, "unauthorized", http.StatusUnauthorized)
			return
		}

		userIDStr := mux.Vars(r)["id"]

		userID, err := strconv.ParseInt(userIDStr, 10, 64)
		if err != nil || userID <= 0 {
			http.Error(w, "invalid id", http.StatusBadRequest)
			return
		}

		/* ================= PAYLOAD ================= */

		var list []permissions.UserPermissionRequest

		if err := json.NewDecoder(r.Body).Decode(&list); err != nil {
			http.Error(w, "bad payload", http.StatusBadRequest)
			return
		}

		repo := permissions.NewPermissionRepository(db)

		/* ================= OLD ================= */

		oldRows, _ := repo.GetUserOverridesByUserID(userID)

		oldMap := map[string]bool{}

		for _, p := range oldRows {
			key := p.Module + ":" + p.Action
			oldMap[key] = p.Allowed
		}

		/* ================= NEW ================= */

		newMap := map[string]bool{}

		for _, p := range list {
			key := p.Module + ":" + p.Action
			newMap[key] = p.Allowed
		}

		/* ================= DIFF ================= */

		var changes []map[string]any

		for key, newVal := range newMap {

			oldVal := oldMap[key]

			if oldVal != newVal {

				parts := strings.Split(key, ":")
				if len(parts) != 2 {
					continue
				}

				changes = append(changes, map[string]any{
					"module": parts[0],
					"action": parts[1],
					"before": oldVal,
					"after":  newVal,
				})
			}
		}

		/* ================= SAVE ================= */

		if err := repo.SaveUserOverrides(userID, list); err != nil {
			http.Error(w, "db error", http.StatusInternalServerError)
			return
		}

		/* ================= AUDIT ================= */

		if len(changes) > 0 && claims != nil {

			var targetUsername string

			_ = db.QueryRow(`
				SELECT username
				FROM mk_dfusr
				WHERE id = $1
			`, userID).Scan(&targetUsername)

			auditlog.Enqueue(r.Context(), auditlog.ActivityLog{

				ActionType:     "user_permission_change",
				ActionCategory: "permission",

				ActionTarget: fmt.Sprintf(
					"/api/users/%d/permissions",
					userID,
				),

				Description: "user permission overrides updated",

				Username: claims.Username,
				RoleCode: claims.RoleCode,
				DfUsrID:  int64(claims.ID),

				TargetDfUsrID:  userID,
				TargetUsername: targetUsername,

				ChangeBefore: map[string]any{
					"permissions": oldRows,
				},

				ChangeAfter: map[string]any{
					"changes": changes,
				},

				IsSuccess: true,
			})
		}

		/* ================= RESPONSE ================= */

		w.Header().Set("Content-Type", "application/json")

		json.NewEncoder(w).Encode(map[string]any{
			"success": true,
		})
	}
}

/* =====================================================
   OPTIONAL METHOD
===================================================== */

func (h *PermissionHandler) SaveUserOverrides(w http.ResponseWriter, r *http.Request) {

	claims, ok := auth.GetClaimsFromContext(r.Context())
	if !ok || claims == nil {
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	}

	userID, _ := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)

	var list []permissions.UserPermissionRequest

	if err := json.NewDecoder(r.Body).Decode(&list); err != nil {
		http.Error(w, "bad payload", 400)
		return
	}

	log.Println("➡️ SAVE USER PERMISSIONS")
	log.Println("USER ID:", userID)
	log.Println("ITEM COUNT:", len(list))

	if err := h.Repo.SaveUserOverrides(userID, list); err != nil {

		log.Println("🔥 USER PERMISSION SAVE ERROR")
		log.Println("ERROR:", err)

		http.Error(w, err.Error(), 500)
		return
	}

	json.NewEncoder(w).Encode(map[string]bool{
		"success": true,
	})
}
