package handlers

import (
	"net/http"
	"strconv"

	"github.com/go-chi/chi/v5"
	"xorm.io/xorm"

	"github.com/forgeo/forgebucket/internal/domain/vulnscan"
	"github.com/forgeo/forgebucket/internal/models"
)

type VulnScanHandler struct {
	db      *xorm.Engine
	scanner *vulnscan.Scanner
}

func NewVulnScanHandler(db *xorm.Engine, scanner *vulnscan.Scanner) *VulnScanHandler {
	return &VulnScanHandler{db: db, scanner: scanner}
}

// List returns all active vulnerability findings for a repo.
// GET /api/v1/repos/{owner}/{repo}/vulnerabilities
func (h *VulnScanHandler) List(w http.ResponseWriter, r *http.Request) {
	repoID, ok := resolveRepoID(h.db, w, r)
	if !ok {
		return
	}

	findings, err := h.scanner.ListFindings(repoID)
	if err != nil {
		jsonError(w, "database error", http.StatusInternalServerError)
		return
	}
	jsonOK(w, findings)
}

// Scan triggers a full vulnerability scan against the latest SBOM.
// POST /api/v1/repos/{owner}/{repo}/vulnerabilities/scan
func (h *VulnScanHandler) Scan(w http.ResponseWriter, r *http.Request) {
	repoID, ok := resolveRepoID(h.db, w, r)
	if !ok {
		return
	}

	findings, err := h.scanner.ScanSBOM(repoID)
	if err != nil {
		jsonError(w, "scan failed: "+err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
	jsonOK(w, findings)
}

// Dismiss acknowledges a vulnerability finding.
// POST /api/v1/repos/{owner}/{repo}/vulnerabilities/{findingID}/dismiss
func (h *VulnScanHandler) Dismiss(w http.ResponseWriter, r *http.Request) {
	repoID, ok := resolveRepoID(h.db, w, r)
	if !ok {
		return
	}
	_ = repoID

	findingID, err := strconv.ParseInt(chi.URLParam(r, "findingID"), 10, 64)
	if err != nil {
		jsonError(w, "invalid finding ID", http.StatusBadRequest)
		return
	}

	username := r.Context().Value("user").(string)

	if err := h.scanner.DismissFindings(findingID, username); err != nil {
		jsonError(w, err.Error(), http.StatusNotFound)
		return
	}
	jsonOK(w, map[string]string{"status": "dismissed"})
}

// ListAll returns active findings across all repos.
// GET /api/v1/vulnerabilities
func (h *VulnScanHandler) ListAll(w http.ResponseWriter, r *http.Request) {
	var findings []models.VulnerabilityFinding
	if err := h.db.Where("dismissed = ?", false).
		OrderBy("cvss_score DESC, detected_at DESC").Find(&findings); err != nil {
		jsonError(w, "database error", http.StatusInternalServerError)
		return
	}
	if findings == nil {
		findings = []models.VulnerabilityFinding{}
	}
	jsonOK(w, findings)
}
