package handlers

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"git.linuxforward.com/byop/byop-engine/models"
	"github.com/gin-gonic/gin"
)

// AutoDeployHandler handles auto-deployment related operations
type AutoDeployHandler struct {
	autoDeploySettings *models.AutoDeploySettings
	settingsMutex      sync.RWMutex
	deploymentQueue    chan *models.AutoDeployRequest
}

// NewAutoDeployHandler creates a new AutoDeployHandler
func NewAutoDeployHandler() *AutoDeployHandler {
	return &AutoDeployHandler{}
}

// RegisterRoutes registers routes for auto-deployment operations
func (h *AutoDeployHandler) RegisterRoutes(r *gin.RouterGroup) {
	r.POST("/client", h.AutoDeployClient)
	r.POST("/webhook", h.AutoDeployWebhook)
	r.PUT("/settings", h.UpdateAutoDeploySettings)
	r.GET("/settings", h.GetAutoDeploySettings)
}

// AutoDeployClient handles requests to deploy for a client
func (h *AutoDeployHandler) AutoDeployClient(c *gin.Context) {
	// Parse the request
	var request *models.AutoDeployRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "Invalid request body",
		})
		return
	}

	// Check if auto-deployment is enabled
	h.settingsMutex.RLock()
	enabled := h.autoDeploySettings.Enabled
	h.settingsMutex.RUnlock()

	if !enabled {
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"error": "Auto-deployment is currently disabled",
		})
		return
	}

	// Queue the deployment request
	select {
	case h.deploymentQueue <- request:
		// Successfully queued
	default:
		// Queue is full
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"error": "Deployment queue is full, try again later",
		})
		return
	}

	// Return a success response
	c.JSON(http.StatusAccepted, gin.H{
		"status":   "queued",
		"message":  "Deployment request has been queued",
		"clientId": request.ClientID,
		"queuedAt": time.Now(),
	})
}

// AutoDeployWebhook handles webhook triggers for auto-deployment
func (h *AutoDeployHandler) AutoDeployWebhook(c *gin.Context) {
	// Parse the webhook payload
	var payload *models.WebhookPayload
	if err := c.ShouldBindJSON(&payload); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "Invalid webhook payload",
		})
		return
	}

	// Validate the webhook signature
	h.settingsMutex.RLock()
	secret := h.autoDeploySettings.WebhookSecret
	enabled := h.autoDeploySettings.Enabled
	h.settingsMutex.RUnlock()

	// This is a simplified signature check, in production use HMAC
	if c.GetHeader("X-Webhook-Signature") != secret {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error": "Invalid webhook signature",
		})
		return
	}

	if !enabled {
		c.JSON(http.StatusServiceUnavailable, gin.H{
			"error": "Auto-deployment is currently disabled",
		})
		return
	}

	// Handle different event types
	switch payload.Event {
	case "client.created":
		// Check if we should auto-deploy for new clients
		h.settingsMutex.RLock()
		autoDeploy := h.autoDeploySettings.AutoDeployNewClients
		h.settingsMutex.RUnlock()

		if autoDeploy && payload.ClientID != "" {
			// Queue a deployment request
			request := &models.AutoDeployRequest{
				ClientID: payload.ClientID,
				// Use defaults for other fields
			}

			select {
			case h.deploymentQueue <- request:
				// Successfully queued
			default:
				// Queue is full
				log.Printf("Deployment queue is full, skipping auto-deployment for client %s", payload.ClientID)
			}
		}

	case "deployment.requested":
		// Handle explicit deployment requests
		if payload.ClientID == "" {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": "client_id is required for deployment requests",
			})
			return
		}

		// Parse the deployment data
		var deployData struct {
			TemplateID string            `json:"template_id"`
			ProviderID string            `json:"provider_id"`
			Region     string            `json:"region"`
			Tags       map[string]string `json:"tags"`
		}

		if err := json.Unmarshal(payload.Data, &deployData); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"error": "Invalid deployment data",
			})
			return
		}

		// Queue the deployment
		request := &models.AutoDeployRequest{
			ClientID:   payload.ClientID,
			TemplateID: deployData.TemplateID,
			ProviderID: deployData.ProviderID,
			Region:     deployData.Region,
			Tags:       deployData.Tags,
		}

		select {
		case h.deploymentQueue <- request:
			// Successfully queued
		default:
			// Queue is full
			c.JSON(http.StatusServiceUnavailable, gin.H{
				"error": "Deployment queue is full, try again later",
			})
			return
		}

	default:
		// Unknown event type
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("Unsupported event type: %s", payload.Event),
		})
		return
	}

	// Return a success response
	c.JSON(http.StatusOK, gin.H{
		"status":    "received",
		"event":     payload.Event,
		"timestamp": time.Now(),
		"requestId": payload.RequestID,
	})
}

// UpdateAutoDeploySettings updates the auto-deployment settings
func (h *AutoDeployHandler) UpdateAutoDeploySettings(c *gin.Context) {
	// Parse the settings
	var settings *models.AutoDeploySettings
	if err := c.ShouldBindJSON(&settings); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "Invalid settings format",
		})
		return
	}

	// Validate settings
	if settings.DefaultProviderID == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "default_provider_id is required",
		})
		return
	}

	if settings.DefaultTemplateID == "" {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "default_template_id is required",
		})
		return
	}

	// Update the settings
	h.settingsMutex.Lock()
	// Keep the webhook secret if not provided
	if settings.WebhookSecret == "" {
		settings.WebhookSecret = h.autoDeploySettings.WebhookSecret
	}
	h.autoDeploySettings = settings
	h.settingsMutex.Unlock()

	// Return the updated settings (without sensitive fields)
	h.settingsMutex.RLock()
	responseSettings := h.autoDeploySettings
	responseSettings.WebhookSecret = "********" // Hide the actual secret
	h.settingsMutex.RUnlock()

	c.JSON(http.StatusOK, responseSettings)
}

// GetAutoDeploySettings returns the current auto-deployment settings
func (h *AutoDeployHandler) GetAutoDeploySettings(c *gin.Context) {
	// Get a copy of the settings
	h.settingsMutex.RLock()
	settings := h.autoDeploySettings
	settings.WebhookSecret = "********" // Hide the actual secret
	h.settingsMutex.RUnlock()

	// Return the settings
	c.JSON(http.StatusOK, settings)
}
