package adapters

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"strings"

	domain2 "epigas.gitea.cloud/RiskRancher/core/pkg/domain"
)

func (h *Handler) HandleGetAdapters(w http.ResponseWriter, r *http.Request) {
	adapters, err := h.Store.GetAdapters(r.Context())
	if err != nil {
		http.Error(w, "Database error", http.StatusInternalServerError)
		return
	}
	json.NewEncoder(w).Encode(adapters)
}

func (h *Handler) HandleCreateAdapter(w http.ResponseWriter, r *http.Request) {
	var adapter domain2.Adapter
	if err := json.NewDecoder(r.Body).Decode(&adapter); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}
	if err := h.Store.SaveAdapter(r.Context(), adapter); err != nil {
		http.Error(w, "Failed to save adapter", http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
}

func (h *Handler) HandleDeleteAdapter(w http.ResponseWriter, r *http.Request) {
	idStr := r.PathValue("id")
	id, err := strconv.Atoi(idStr)
	if err != nil {
		http.Error(w, "Invalid adapter ID", http.StatusBadRequest)
		return
	}

	if err := h.Store.DeleteAdapter(r.Context(), id); err != nil {
		http.Error(w, "Failed to delete adapter", http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

func getJSONValue(data interface{}, path string) interface{} {
	if path == "" || path == "." {
		return data // The root IS the array
	}
	keys := strings.Split(path, ".")
	current := data
	for _, key := range keys {
		if m, ok := current.(map[string]interface{}); ok {
			current = m[key]
		} else {
			return nil // Path broke
		}
	}
	return current
}

func interfaceToString(val interface{}) string {
	if val == nil {
		return ""
	}
	if str, ok := val.(string); ok {
		return str
	}
	return "" // Could expand this to handle ints/floats if needed
}

// HandleAdapterIngest dynamically maps deeply nested JSON arrays into Tickets
func (h *Handler) HandleAdapterIngest(w http.ResponseWriter, r *http.Request) {
	adapterName := r.PathValue("name")
	adapter, err := h.Store.GetAdapterByName(r.Context(), adapterName)
	if err != nil {
		http.Error(w, "Adapter not found", http.StatusNotFound)
		return
	}

	var rawData interface{}
	if err := json.NewDecoder(r.Body).Decode(&rawData); err != nil {
		http.Error(w, "Invalid JSON payload", http.StatusBadRequest)
		return
	}

	findingsNode := getJSONValue(rawData, adapter.FindingsPath)
	findingsArray, ok := findingsNode.([]interface{})
	if !ok {
		http.Error(w, "Findings path did not resolve to a JSON array", http.StatusBadRequest)
		return
	}

	type groupKey struct {
		Source string
		Asset  string
	}
	groupedTickets := make(map[groupKey][]domain2.Ticket)

	for _, item := range findingsArray {
		finding, ok := item.(map[string]interface{})
		if !ok {
			continue
		}

		ticket := domain2.Ticket{
			Source:                 adapter.SourceName,
			Status:                 "Waiting to be Triaged", // Explicitly set status
			Title:                  interfaceToString(finding[adapter.MappingTitle]),
			AssetIdentifier:        interfaceToString(finding[adapter.MappingAsset]),
			Severity:               interfaceToString(finding[adapter.MappingSeverity]),
			Description:            interfaceToString(finding[adapter.MappingDescription]),
			RecommendedRemediation: interfaceToString(finding[adapter.MappingRemediation]),
		}

		if ticket.Title != "" && ticket.AssetIdentifier != "" {
			hashInput := ticket.Source + "|" + ticket.AssetIdentifier + "|" + ticket.Title
			hash := sha256.Sum256([]byte(hashInput))
			ticket.DedupeHash = hex.EncodeToString(hash[:])
			key := groupKey{Source: ticket.Source, Asset: ticket.AssetIdentifier}
			groupedTickets[key] = append(groupedTickets[key], ticket)
		}
	}

	for key, batch := range groupedTickets {
		err := h.Store.ProcessIngestionBatch(r.Context(), key.Source, key.Asset, batch)
		if err != nil {
			log.Printf("🔥 JSON Ingestion Error for Asset %s: %v", key.Asset, err)
			// 🚀 LOG THE BATCH FAILURE
			h.Store.LogSync(r.Context(), key.Source, "Failed", len(batch), err.Error())
			http.Error(w, "Database error processing JSON batch", http.StatusInternalServerError)
			return
		} else {
			// 🚀 LOG THE SUCCESS
			h.Store.LogSync(r.Context(), key.Source, "Success", len(batch), "")
		}
	}

	w.WriteHeader(http.StatusCreated)
}
