package reports

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"github.com/TaruLab/keluargamart-backend/internal/auth"
	"github.com/TaruLab/keluargamart-backend/pkg/httpresponse"
	"github.com/TaruLab/keluargamart-backend/pkg/middleware"
	"github.com/go-chi/chi/v5"
)

const WidgetPolicyKey = "dashboard_widgets_policy"

var DefaultRoleWidgets = map[string][]string{
	"admin": {
		"net-cashflow", "pending-invoices", "supplier-debts", "pnl-summary", "cashflow",
		"aging-receivables", "cash-disbursement", "period-status",
		"month-revenue", "today-revenue", "revenue-trend", "recent-orders",
		"category-performance", "top-products", "recent-noo", "ao-performance",
		"sales-targets", "sales-visits", "lhpp-summary",
		"stock-value", "low-stock", "pending-pos", "goods-receipts", "delivery-orders", "stock-opname",
		"active-shifts", "pos-quick-access",
		"hr-attendance-summary", "hr-leaves", "hr-employees",
		"operational-alerts", "support-tickets",
	},
	"owner": {
		"net-cashflow", "pending-invoices", "supplier-debts", "pnl-summary", "cashflow",
		"aging-receivables", "cash-disbursement", "period-status",
		"month-revenue", "today-revenue", "revenue-trend", "recent-orders",
		"category-performance", "top-products", "recent-noo", "ao-performance",
		"sales-targets", "sales-visits", "lhpp-summary",
		"stock-value", "low-stock", "pending-pos", "goods-receipts", "delivery-orders", "stock-opname",
		"active-shifts", "pos-quick-access",
		"hr-attendance-summary", "hr-leaves", "hr-employees",
		"operational-alerts", "support-tickets",
	},
	"gm": {
		"net-cashflow", "pending-invoices", "supplier-debts", "pnl-summary", "cashflow",
		"aging-receivables", "period-status",
		"month-revenue", "today-revenue", "revenue-trend", "recent-orders",
		"category-performance", "top-products", "recent-noo", "ao-performance",
		"sales-targets", "sales-visits", "lhpp-summary",
		"stock-value", "low-stock", "pending-pos", "goods-receipts", "delivery-orders", "stock-opname",
		"active-shifts", "hr-attendance-summary", "hr-leaves", "hr-employees",
		"operational-alerts", "support-tickets",
	},
	"bm": {
		"net-cashflow", "pending-invoices", "supplier-debts", "pnl-summary", "cashflow",
		"month-revenue", "today-revenue", "revenue-trend", "recent-orders",
		"top-products", "recent-noo", "ao-performance", "sales-targets", "sales-visits", "lhpp-summary",
		"stock-value", "low-stock", "pending-pos", "goods-receipts", "delivery-orders",
		"active-shifts", "operational-alerts", "support-tickets",
	},
	"spv": {
		"month-revenue", "today-revenue", "revenue-trend", "recent-orders",
		"top-products", "category-performance", "recent-noo", "ao-performance",
		"sales-targets", "sales-visits", "lhpp-summary",
		"pending-invoices", "low-stock",
		"operational-alerts", "support-tickets",
	},
	"sales": {
		"month-revenue", "today-revenue", "revenue-trend", "recent-orders",
		"top-products", "category-performance", "recent-noo", "ao-performance",
		"sales-targets", "sales-visits",
		"operational-alerts", "support-tickets",
	},
	"finance": {
		"net-cashflow", "pending-invoices", "supplier-debts", "pnl-summary", "cashflow",
		"aging-receivables", "cash-disbursement", "period-status", "stock-value",
		"revenue-trend", "lhpp-summary", "pending-pos",
		"operational-alerts", "support-tickets",
	},
	"finance_head": {
		"net-cashflow", "pending-invoices", "supplier-debts", "pnl-summary", "cashflow",
		"aging-receivables", "cash-disbursement", "period-status", "stock-value",
		"revenue-trend", "lhpp-summary", "pending-pos",
		"operational-alerts", "support-tickets",
	},
	"warehouse": {
		"low-stock", "stock-value", "pending-pos", "goods-receipts", "delivery-orders", "stock-opname",
		"top-products", "recent-orders", "operational-alerts", "support-tickets",
	},
	"store_manager": {
		"today-revenue", "month-revenue", "revenue-trend", "recent-orders", "top-products",
		"active-shifts", "pos-quick-access", "cash-disbursement",
		"low-stock", "stock-value", "stock-opname",
		"operational-alerts", "support-tickets",
	},
	"cashier": {
		"today-revenue", "active-shifts", "pos-quick-access", "top-products", "cash-disbursement", "support-tickets",
	},
	"hr_manager": {
		"hr-attendance-summary", "hr-leaves", "hr-employees", "operational-alerts", "support-tickets",
	},
	"hr_staff": {
		"hr-attendance-summary", "hr-leaves", "hr-employees", "operational-alerts", "support-tickets",
	},
	"employee": {
		"hr-attendance-summary", "support-tickets",
	},
	"buyer": {
		"supplier-debts", "pending-pos", "top-products", "support-tickets",
	},
}

func copyDefaults() map[string][]string {
	out := make(map[string][]string, len(DefaultRoleWidgets))
	for k, v := range DefaultRoleWidgets {
		cp := make([]string, len(v))
		copy(cp, v)
		out[k] = cp
	}
	return out
}

func (h *Handler) loadPolicy(r *http.Request) map[string][]string {
	policy := copyDefaults()
	raw, err := h.svc.GetAppSetting(r.Context(), WidgetPolicyKey)
	if err == nil && len(raw) > 0 {
		var custom map[string][]string
		if err := json.Unmarshal(raw, &custom); err == nil {
			for k, v := range custom {
				policy[k] = v
			}
		}
	}
	return policy
}

func (h *Handler) GetWidgetPolicy(w http.ResponseWriter, r *http.Request) {
	policy := h.loadPolicy(r)
	httpresponse.OK(w, http.StatusOK, middleware.RequestIDFrom(r.Context()), policy)
}

func (h *Handler) SetRoleWidgetPolicy(w http.ResponseWriter, r *http.Request) {
	role := chi.URLParam(r, "role")
	if strings.TrimSpace(role) == "" {
		httpresponse.Error(w, http.StatusBadRequest, middleware.RequestIDFrom(r.Context()),
			httpresponse.CodeValidation, "Role tidak valid", nil)
		return
	}

	var req struct {
		Widgets []string `json:"widgets"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httpresponse.Error(w, http.StatusBadRequest, middleware.RequestIDFrom(r.Context()),
			httpresponse.CodeValidation, "Format body tidak valid", nil)
		return
	}

	policy := h.loadPolicy(r)
	policy[role] = req.Widgets

	raw, err := json.Marshal(policy)
	if err != nil {
		httpresponse.Internal(w, middleware.RequestIDFrom(r.Context()), nil, err)
		return
	}

	if err := h.svc.UpsertAppSetting(r.Context(), WidgetPolicyKey, raw); err != nil {
		httpresponse.Internal(w, middleware.RequestIDFrom(r.Context()), nil, err)
		return
	}

	httpresponse.OK(w, http.StatusOK, middleware.RequestIDFrom(r.Context()), policy)
}

type UserWidgetPreference struct {
	Widgets []string `json:"widgets"`
	Order   []string `json:"order,omitempty"`
}

func (h *Handler) GetUserWidgetPreferences(w http.ResponseWriter, r *http.Request) {
	u := auth.UserFrom(r.Context())
	if u == nil {
		httpresponse.Error(w, http.StatusUnauthorized, middleware.RequestIDFrom(r.Context()),
			httpresponse.CodeAuthentication, "Unauthenticated", nil)
		return
	}

	key := fmt.Sprintf("dashboard_widgets_user_%d", u.ID)
	raw, err := h.svc.GetAppSetting(r.Context(), key)
	if err == nil && len(raw) > 0 {
		var pref UserWidgetPreference
		if err := json.Unmarshal(raw, &pref); err == nil && len(pref.Widgets) > 0 {
			httpresponse.OK(w, http.StatusOK, middleware.RequestIDFrom(r.Context()), pref)
			return
		}
	}

	// Fallback to role policy defaults
	policy := h.loadPolicy(r)
	roleName := string(u.Role)
	widgets, ok := policy[roleName]
	if !ok {
		widgets = DefaultRoleWidgets["employee"]
	}
	pref := UserWidgetPreference{
		Widgets: widgets,
		Order:   widgets,
	}
	httpresponse.OK(w, http.StatusOK, middleware.RequestIDFrom(r.Context()), pref)
}

func (h *Handler) SetUserWidgetPreferences(w http.ResponseWriter, r *http.Request) {
	u := auth.UserFrom(r.Context())
	if u == nil {
		httpresponse.Error(w, http.StatusUnauthorized, middleware.RequestIDFrom(r.Context()),
			httpresponse.CodeAuthentication, "Unauthenticated", nil)
		return
	}

	var pref UserWidgetPreference
	if err := json.NewDecoder(r.Body).Decode(&pref); err != nil {
		httpresponse.Error(w, http.StatusBadRequest, middleware.RequestIDFrom(r.Context()),
			httpresponse.CodeValidation, "Format body tidak valid", nil)
		return
	}

	key := fmt.Sprintf("dashboard_widgets_user_%d", u.ID)
	raw, err := json.Marshal(pref)
	if err != nil {
		httpresponse.Internal(w, middleware.RequestIDFrom(r.Context()), nil, err)
		return
	}

	if err := h.svc.UpsertAppSetting(r.Context(), key, raw); err != nil {
		httpresponse.Internal(w, middleware.RequestIDFrom(r.Context()), nil, err)
		return
	}

	httpresponse.OK(w, http.StatusOK, middleware.RequestIDFrom(r.Context()), pref)
}

func (h *Handler) ResetUserWidgetPreferences(w http.ResponseWriter, r *http.Request) {
	u := auth.UserFrom(r.Context())
	if u == nil {
		httpresponse.Error(w, http.StatusUnauthorized, middleware.RequestIDFrom(r.Context()),
			httpresponse.CodeAuthentication, "Unauthenticated", nil)
		return
	}

	key := fmt.Sprintf("dashboard_widgets_user_%d", u.ID)
	_ = h.svc.DeleteAppSetting(r.Context(), key)

	policy := h.loadPolicy(r)
	roleName := string(u.Role)
	widgets, ok := policy[roleName]
	if !ok {
		widgets = DefaultRoleWidgets["employee"]
	}
	pref := UserWidgetPreference{
		Widgets: widgets,
		Order:   widgets,
	}
	httpresponse.OK(w, http.StatusOK, middleware.RequestIDFrom(r.Context()), pref)
}
