package handlers

import (
	"bytes"
	"io"
	"net/http"
	"time"

	"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
	"github.com/breakpilot/ai-compliance-sdk/internal/roadmap"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// RoadmapHandlers handles roadmap-related HTTP requests
type RoadmapHandlers struct {
	store  *roadmap.Store
	parser *roadmap.Parser
}

// NewRoadmapHandlers creates new roadmap handlers
func NewRoadmapHandlers(store *roadmap.Store) *RoadmapHandlers {
	return &RoadmapHandlers{
		store:  store,
		parser: roadmap.NewParser(),
	}
}

// ============================================================================
// Roadmap CRUD
// ============================================================================

// CreateRoadmap creates a new roadmap
// POST /sdk/v1/roadmaps
func (h *RoadmapHandlers) CreateRoadmap(c *gin.Context) {
	var req roadmap.CreateRoadmapRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	tenantID := rbac.GetTenantID(c)
	userID := rbac.GetUserID(c)

	r := &roadmap.Roadmap{
		TenantID:     tenantID,
		Title:        req.Title,
		Description:  req.Description,
		AssessmentID: req.AssessmentID,
		PortfolioID:  req.PortfolioID,
		StartDate:    req.StartDate,
		TargetDate:   req.TargetDate,
		Status:       "draft",
		CreatedBy:    userID,
	}

	if err := h.store.CreateRoadmap(c.Request.Context(), r); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, roadmap.CreateRoadmapResponse{Roadmap: *r})
}

// ListRoadmaps lists roadmaps for the tenant
// GET /sdk/v1/roadmaps
func (h *RoadmapHandlers) ListRoadmaps(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)

	filters := &roadmap.RoadmapFilters{
		Status: c.Query("status"),
		Limit:  50,
	}

	if assessmentID := c.Query("assessment_id"); assessmentID != "" {
		if id, err := uuid.Parse(assessmentID); err == nil {
			filters.AssessmentID = &id
		}
	}

	roadmaps, err := h.store.ListRoadmaps(c.Request.Context(), tenantID, filters)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

// GetRoadmap retrieves a roadmap by ID
// GET /sdk/v1/roadmaps/:id
func (h *RoadmapHandlers) GetRoadmap(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

	r, err := h.store.GetRoadmap(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if r == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "roadmap not found"})
		return
	}

	// Get items
	items, err := h.store.ListItems(c.Request.Context(), id, nil)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Get stats
	stats, _ := h.store.GetRoadmapStats(c.Request.Context(), id)

	c.JSON(http.StatusOK, gin.H{
		"roadmap": r,
		"items":   items,
		"stats":   stats,
	})
}

// UpdateRoadmap updates a roadmap
// PUT /sdk/v1/roadmaps/:id
func (h *RoadmapHandlers) UpdateRoadmap(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

	r, err := h.store.GetRoadmap(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if r == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "roadmap not found"})
		return
	}

	var req roadmap.CreateRoadmapRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	r.Title = req.Title
	r.Description = req.Description
	r.AssessmentID = req.AssessmentID
	r.PortfolioID = req.PortfolioID
	r.StartDate = req.StartDate
	r.TargetDate = req.TargetDate

	if err := h.store.UpdateRoadmap(c.Request.Context(), r); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"roadmap": r})
}

// DeleteRoadmap deletes a roadmap
// DELETE /sdk/v1/roadmaps/:id
func (h *RoadmapHandlers) DeleteRoadmap(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

	if err := h.store.DeleteRoadmap(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "roadmap deleted"})
}

// GetRoadmapStats returns statistics for a roadmap
// GET /sdk/v1/roadmaps/:id/stats
func (h *RoadmapHandlers) GetRoadmapStats(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

	stats, err := h.store.GetRoadmapStats(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, stats)
}

// ============================================================================
// RoadmapItem CRUD
// ============================================================================

// CreateItem creates a new roadmap item
// POST /sdk/v1/roadmaps/:id/items
func (h *RoadmapHandlers) CreateItem(c *gin.Context) {
	roadmapID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid roadmap ID"})
		return
	}

	var input roadmap.RoadmapItemInput
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	item := &roadmap.RoadmapItem{
		RoadmapID:     roadmapID,
		Title:         input.Title,
		Description:   input.Description,
		Category:      input.Category,
		Priority:      input.Priority,
		Status:        input.Status,
		ControlID:     input.ControlID,
		RegulationRef: input.RegulationRef,
		GapID:         input.GapID,
		EffortDays:    input.EffortDays,
		AssigneeName:  input.AssigneeName,
		Department:    input.Department,
		PlannedStart:  input.PlannedStart,
		PlannedEnd:    input.PlannedEnd,
		Notes:         input.Notes,
	}

	if err := h.store.CreateItem(c.Request.Context(), item); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Update roadmap progress
	h.store.UpdateRoadmapProgress(c.Request.Context(), roadmapID)

	c.JSON(http.StatusCreated, gin.H{"item": item})
}

// ListItems lists items for a roadmap
// GET /sdk/v1/roadmaps/:id/items
func (h *RoadmapHandlers) ListItems(c *gin.Context) {
	roadmapID, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid roadmap ID"})
		return
	}

	filters := &roadmap.RoadmapItemFilters{
		SearchQuery: c.Query("search"),
		Limit:       100,
	}

	if status := c.Query("status"); status != "" {
		filters.Status = roadmap.ItemStatus(status)
	}
	if priority := c.Query("priority"); priority != "" {
		filters.Priority = roadmap.ItemPriority(priority)
	}
	if category := c.Query("category"); category != "" {
		filters.Category = roadmap.ItemCategory(category)
	}
	if controlID := c.Query("control_id"); controlID != "" {
		filters.ControlID = controlID
	}

	items, err := h.store.ListItems(c.Request.Context(), roadmapID, filters)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

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

// GetItem retrieves a roadmap item
// GET /sdk/v1/roadmap-items/:id
func (h *RoadmapHandlers) GetItem(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

	item, err := h.store.GetItem(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if item == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "item not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"item": item})
}

// UpdateItem updates a roadmap item
// PUT /sdk/v1/roadmap-items/:id
func (h *RoadmapHandlers) UpdateItem(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

	item, err := h.store.GetItem(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if item == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "item not found"})
		return
	}

	var input roadmap.RoadmapItemInput
	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Update fields
	item.Title = input.Title
	item.Description = input.Description
	if input.Category != "" {
		item.Category = input.Category
	}
	if input.Priority != "" {
		item.Priority = input.Priority
	}
	if input.Status != "" {
		item.Status = input.Status
	}
	item.ControlID = input.ControlID
	item.RegulationRef = input.RegulationRef
	item.GapID = input.GapID
	item.EffortDays = input.EffortDays
	item.AssigneeName = input.AssigneeName
	item.Department = input.Department
	item.PlannedStart = input.PlannedStart
	item.PlannedEnd = input.PlannedEnd
	item.Notes = input.Notes

	if err := h.store.UpdateItem(c.Request.Context(), item); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Update roadmap progress
	h.store.UpdateRoadmapProgress(c.Request.Context(), item.RoadmapID)

	c.JSON(http.StatusOK, gin.H{"item": item})
}

// UpdateItemStatus updates just the status of a roadmap item
// PATCH /sdk/v1/roadmap-items/:id/status
func (h *RoadmapHandlers) UpdateItemStatus(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

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

	item, err := h.store.GetItem(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if item == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "item not found"})
		return
	}

	item.Status = req.Status

	// Set actual dates
	now := time.Now().UTC()
	if req.Status == roadmap.ItemStatusInProgress && item.ActualStart == nil {
		item.ActualStart = &now
	}
	if req.Status == roadmap.ItemStatusCompleted && item.ActualEnd == nil {
		item.ActualEnd = &now
	}

	if err := h.store.UpdateItem(c.Request.Context(), item); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Update roadmap progress
	h.store.UpdateRoadmapProgress(c.Request.Context(), item.RoadmapID)

	c.JSON(http.StatusOK, gin.H{"item": item})
}

// DeleteItem deletes a roadmap item
// DELETE /sdk/v1/roadmap-items/:id
func (h *RoadmapHandlers) DeleteItem(c *gin.Context) {
	id, err := uuid.Parse(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid ID"})
		return
	}

	item, err := h.store.GetItem(c.Request.Context(), id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if item == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "item not found"})
		return
	}

	roadmapID := item.RoadmapID

	if err := h.store.DeleteItem(c.Request.Context(), id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Update roadmap progress
	h.store.UpdateRoadmapProgress(c.Request.Context(), roadmapID)

	c.JSON(http.StatusOK, gin.H{"message": "item deleted"})
}

// ============================================================================
// Import Workflow
// ============================================================================

// UploadImport handles file upload for import
// POST /sdk/v1/roadmaps/import/upload
func (h *RoadmapHandlers) UploadImport(c *gin.Context) {
	tenantID := rbac.GetTenantID(c)
	userID := rbac.GetUserID(c)

	// Get file from form
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "file is required"})
		return
	}
	defer file.Close()

	// Read file content
	buf := bytes.Buffer{}
	if _, err := io.Copy(&buf, file); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to read file"})
		return
	}

	// Detect format
	format := roadmap.ImportFormat("")
	filename := header.Filename
	contentType := header.Header.Get("Content-Type")

	// Create import job
	job := &roadmap.ImportJob{
		TenantID:    tenantID,
		Filename:    filename,
		FileSize:    header.Size,
		ContentType: contentType,
		Status:      "pending",
		CreatedBy:   userID,
	}

	if err := h.store.CreateImportJob(c.Request.Context(), job); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Parse the file
	job.Status = "parsing"
	h.store.UpdateImportJob(c.Request.Context(), job)

	result, err := h.parser.ParseFile(buf.Bytes(), filename, contentType)
	if err != nil {
		job.Status = "failed"
		job.ErrorMessage = err.Error()
		h.store.UpdateImportJob(c.Request.Context(), job)

		c.JSON(http.StatusBadRequest, gin.H{
			"error":  "failed to parse file",
			"detail": err.Error(),
		})
		return
	}

	// Update job with parsed data
	job.Status = "parsed"
	job.Format = format
	job.TotalRows = result.TotalRows
	job.ValidRows = result.ValidRows
	job.InvalidRows = result.InvalidRows
	job.ParsedItems = result.Items

	h.store.UpdateImportJob(c.Request.Context(), job)

	c.JSON(http.StatusOK, roadmap.ImportParseResponse{
		JobID:       job.ID,
		Status:      job.Status,
		TotalRows:   result.TotalRows,
		ValidRows:   result.ValidRows,
		InvalidRows: result.InvalidRows,
		Items:       result.Items,
		ColumnMap:   buildColumnMap(result.Columns),
	})
}

// GetImportJob returns the status of an import job
// GET /sdk/v1/roadmaps/import/:jobId
func (h *RoadmapHandlers) GetImportJob(c *gin.Context) {
	jobID, err := uuid.Parse(c.Param("jobId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid job ID"})
		return
	}

	job, err := h.store.GetImportJob(c.Request.Context(), jobID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if job == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "import job not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"job":   job,
		"items": job.ParsedItems,
	})
}

// ConfirmImport confirms and executes the import
// POST /sdk/v1/roadmaps/import/:jobId/confirm
func (h *RoadmapHandlers) ConfirmImport(c *gin.Context) {
	jobID, err := uuid.Parse(c.Param("jobId"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid job ID"})
		return
	}

	var req roadmap.ImportConfirmRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	job, err := h.store.GetImportJob(c.Request.Context(), jobID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	if job == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "import job not found"})
		return
	}

	if job.Status != "parsed" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error":  "job is not ready for confirmation",
			"status": job.Status,
		})
		return
	}

	tenantID := rbac.GetTenantID(c)
	userID := rbac.GetUserID(c)

	// Create or use existing roadmap
	var roadmapID uuid.UUID
	if req.RoadmapID != nil {
		roadmapID = *req.RoadmapID
		// Verify roadmap exists
		r, err := h.store.GetRoadmap(c.Request.Context(), roadmapID)
		if err != nil || r == nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "roadmap not found"})
			return
		}
	} else {
		// Create new roadmap
		title := req.RoadmapTitle
		if title == "" {
			title = "Imported Roadmap - " + job.Filename
		}

		r := &roadmap.Roadmap{
			TenantID:  tenantID,
			Title:     title,
			Status:    "active",
			CreatedBy: userID,
		}

		if err := h.store.CreateRoadmap(c.Request.Context(), r); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		roadmapID = r.ID
	}

	// Determine which rows to import
	selectedRows := make(map[int]bool)
	if len(req.SelectedRows) > 0 {
		for _, row := range req.SelectedRows {
			selectedRows[row] = true
		}
	}

	// Convert parsed items to roadmap items
	var items []roadmap.RoadmapItem
	var importedCount, skippedCount int

	for i, parsed := range job.ParsedItems {
		// Skip invalid items
		if !parsed.IsValid {
			skippedCount++
			continue
		}

		// Skip unselected rows if selection was specified
		if len(selectedRows) > 0 && !selectedRows[parsed.RowNumber] {
			skippedCount++
			continue
		}

		item := roadmap.RoadmapItem{
			RoadmapID:     roadmapID,
			Title:         parsed.Data.Title,
			Description:   parsed.Data.Description,
			Category:      parsed.Data.Category,
			Priority:      parsed.Data.Priority,
			Status:        parsed.Data.Status,
			ControlID:     parsed.Data.ControlID,
			RegulationRef: parsed.Data.RegulationRef,
			GapID:         parsed.Data.GapID,
			EffortDays:    parsed.Data.EffortDays,
			AssigneeName:  parsed.Data.AssigneeName,
			Department:    parsed.Data.Department,
			PlannedStart:  parsed.Data.PlannedStart,
			PlannedEnd:    parsed.Data.PlannedEnd,
			Notes:         parsed.Data.Notes,
			SourceRow:     parsed.RowNumber,
			SourceFile:    job.Filename,
			SortOrder:     i,
		}

		// Apply auto-mappings if requested
		if req.ApplyMappings {
			if parsed.MatchedControl != "" {
				item.ControlID = parsed.MatchedControl
			}
			if parsed.MatchedRegulation != "" {
				item.RegulationRef = parsed.MatchedRegulation
			}
			if parsed.MatchedGap != "" {
				item.GapID = parsed.MatchedGap
			}
		}

		// Set defaults
		if item.Status == "" {
			item.Status = roadmap.ItemStatusPlanned
		}
		if item.Priority == "" {
			item.Priority = roadmap.ItemPriorityMedium
		}
		if item.Category == "" {
			item.Category = roadmap.ItemCategoryTechnical
		}

		items = append(items, item)
		importedCount++
	}

	// Bulk create items
	if len(items) > 0 {
		if err := h.store.BulkCreateItems(c.Request.Context(), items); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

	// Update roadmap progress
	h.store.UpdateRoadmapProgress(c.Request.Context(), roadmapID)

	// Update job status
	now := time.Now().UTC()
	job.Status = "completed"
	job.RoadmapID = &roadmapID
	job.ImportedItems = importedCount
	job.CompletedAt = &now
	h.store.UpdateImportJob(c.Request.Context(), job)

	c.JSON(http.StatusOK, roadmap.ImportConfirmResponse{
		RoadmapID:     roadmapID,
		ImportedItems: importedCount,
		SkippedItems:  skippedCount,
		Message:       "Import completed successfully",
	})
}

// ============================================================================
// Helper Functions
// ============================================================================

func buildColumnMap(columns []roadmap.DetectedColumn) map[string]string {
	result := make(map[string]string)
	for _, col := range columns {
		if col.MappedTo != "" {
			result[col.Header] = col.MappedTo
		}
	}
	return result
}
