// Package api provides HTTP handlers for the Security Scanner
package api

import (
	"net/http"

	"github.com/breakpilot/compliance-sdk/services/security-scanner/internal/scanner"
	"github.com/gin-gonic/gin"
)

// ScanRequest represents a scan request
type ScanRequest struct {
	Tools        []string `json:"tools"`
	TargetPath   string   `json:"target_path"`
	ExcludePaths []string `json:"exclude_paths"`
}

// StartScan starts a new security scan
func StartScan(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		var req ScanRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		tools := req.Tools
		if len(tools) == 0 {
			tools = manager.AvailableTools()
		}

		scan := manager.StartScan(tools, req.TargetPath)

		c.JSON(http.StatusAccepted, gin.H{
			"scan_id":    scan.ID,
			"status":     scan.Status,
			"tools":      scan.Tools,
			"started_at": scan.StartedAt,
		})
	}
}

// GetScanStatus returns the status of a scan
func GetScanStatus(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		scanID := c.Param("scanId")
		scan := manager.GetScan(scanID)

		if scan == nil {
			c.JSON(http.StatusNotFound, gin.H{"error": "Scan not found"})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"scan_id":      scan.ID,
			"status":       scan.Status,
			"started_at":   scan.StartedAt,
			"completed_at": scan.CompletedAt,
			"summary":      scan.Summary,
		})
	}
}

// GetScanResults returns the results of a scan
func GetScanResults(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		scanID := c.Param("scanId")
		scan := manager.GetScan(scanID)

		if scan == nil {
			c.JSON(http.StatusNotFound, gin.H{"error": "Scan not found"})
			return
		}

		c.JSON(http.StatusOK, scan)
	}
}

// GetFindings returns all findings
func GetFindings(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		findings := manager.GetAllFindings()

		severity := c.Query("severity")
		tool := c.Query("tool")
		status := c.Query("status")

		// Filter findings
		filtered := []scanner.Finding{}
		for _, f := range findings {
			if severity != "" && f.Severity != severity {
				continue
			}
			if tool != "" && f.Tool != tool {
				continue
			}
			if status != "" && f.Status != status {
				continue
			}
			filtered = append(filtered, f)
		}

		c.JSON(http.StatusOK, gin.H{
			"findings": filtered,
			"total":    len(filtered),
		})
	}
}

// GetFinding returns a specific finding
func GetFinding(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		findingID := c.Param("findingId")
		findings := manager.GetAllFindings()

		for _, f := range findings {
			if f.ID == findingID {
				c.JSON(http.StatusOK, f)
				return
			}
		}

		c.JSON(http.StatusNotFound, gin.H{"error": "Finding not found"})
	}
}

// UpdateFindingStatus updates the status of a finding
func UpdateFindingStatus(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		findingID := c.Param("findingId")

		var req struct {
			Status string `json:"status" binding:"required"`
		}
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if manager.UpdateFindingStatus(findingID, req.Status) {
			c.JSON(http.StatusOK, gin.H{
				"id":     findingID,
				"status": req.Status,
			})
		} else {
			c.JSON(http.StatusNotFound, gin.H{"error": "Finding not found"})
		}
	}
}

// GenerateSBOM generates a Software Bill of Materials
func GenerateSBOM(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		var req struct {
			TargetPath string `json:"target_path"`
		}
		c.ShouldBindJSON(&req)

		sbom := manager.GenerateSBOM(req.TargetPath)

		c.JSON(http.StatusOK, sbom)
	}
}

// GetSBOM returns an SBOM by ID
func GetSBOM(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		// In production, retrieve from storage
		sbom := manager.GenerateSBOM("")
		c.JSON(http.StatusOK, sbom)
	}
}

// ExportSBOM exports an SBOM in the specified format
func ExportSBOM(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		format := c.Param("format")

		sbom := manager.GenerateSBOM("")
		sbom.Format = format

		var contentType string
		switch format {
		case "cyclonedx":
			contentType = "application/vnd.cyclonedx+json"
		case "spdx":
			contentType = "application/spdx+json"
		default:
			c.JSON(http.StatusBadRequest, gin.H{"error": "Unsupported format"})
			return
		}

		c.Header("Content-Type", contentType)
		c.Header("Content-Disposition", "attachment; filename=sbom."+format+".json")
		c.JSON(http.StatusOK, sbom)
	}
}

// GetRecommendations returns security recommendations
func GetRecommendations(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		recs := manager.GetRecommendations()
		c.JSON(http.StatusOK, gin.H{
			"recommendations": recs,
			"total":           len(recs),
		})
	}
}

// GetToolsStatus returns the status of all tools
func GetToolsStatus(manager *scanner.Manager) gin.HandlerFunc {
	return func(c *gin.Context) {
		tools := manager.GetTools()
		c.JSON(http.StatusOK, gin.H{"tools": tools})
	}
}
