package handler

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"

	caasmmodel "security-center-backend/internal/modules/caasm/model"
	"security-center-backend/internal/modules/caasm/queue"
	"security-center-backend/internal/modules/caasm/repository"
	"security-center-backend/internal/modules/caasm/service"
	"security-center-backend/internal/pkg/logger"
	"security-center-backend/internal/pkg/response"
)

// WebhookHandler handles incoming webhook events from cloud providers
type WebhookHandler struct {
	cloudAcctSvc *service.CloudAccountService
	jobQueue     queue.JobQueueInterface
	logger       *logger.Logger
	accounts     repository.CloudAccountRepository
}

func NewWebhookHandler(cloudAcctSvc *service.CloudAccountService, jobQueue queue.JobQueueInterface, log *logger.Logger, accounts repository.CloudAccountRepository) *WebhookHandler {
	return &WebhookHandler{
		cloudAcctSvc: cloudAcctSvc,
		jobQueue:     jobQueue,
		logger:       log,
		accounts:     accounts,
	}
}

// RegisterRoutes registers webhook routes
func (h *WebhookHandler) RegisterRoutes(rg *gin.RouterGroup) {
	rg.POST("/caasm/webhooks/aws", h.HandleAWSNotification)
}

// AWSEventBridgeNotification represents an AWS EventBridge notification
type AWSEventBridgeNotification struct {
	Version    string                 `json:"version"`
	ID         string                 `json:"id"`
	DetailType string                 `json:"detail-type"`
	Source     string                 `json:"source"`
	Account    string                 `json:"account"`
	Time       time.Time              `json:"time"`
	Region     string                 `json:"region"`
	Resources  []string               `json:"resources"`
	Detail     map[string]interface{} `json:"detail"`
}

// AWSSNSMessage represents an SNS message wrapper
type AWSSNSMessage struct {
	Type             string    `json:"Type"`
	MessageID        string    `json:"MessageId"`
	TopicArn         string    `json:"TopicArn"`
	Subject          string    `json:"Subject"`
	Message          string    `json:"Message"`
	Timestamp        time.Time `json:"Timestamp"`
	SignatureVersion string    `json:"SignatureVersion"`
	Signature        string    `json:"Signature"`
	SigningCertURL   string    `json:"SigningCertURL"`
	UnsubscribeURL   string    `json:"UnsubscribeURL"`
}

// HandleAWSNotification processes AWS SNS/EventBridge notifications
func (h *WebhookHandler) HandleAWSNotification(c *gin.Context) {
	var snsMessage AWSSNSMessage
	if err := c.ShouldBindJSON(&snsMessage); err != nil {
		h.logger.Warn("failed to parse SNS message", "error", err)
		response.Error(c, http.StatusBadRequest, "invalid SNS message format")
		return
	}

	// Handle subscription confirmation
	if snsMessage.Type == "SubscriptionConfirmation" {
		h.logger.Info("received SNS subscription confirmation", "topic", snsMessage.TopicArn)
		// In production, you would confirm the subscription by visiting the SubscribeURL
		response.Success(c, gin.H{"message": "subscription confirmation received"})
		return
	}

	// Parse the actual EventBridge notification from the SNS message
	var event AWSEventBridgeNotification
	if err := json.Unmarshal([]byte(snsMessage.Message), &event); err != nil {
		h.logger.Warn("failed to parse EventBridge notification", "error", err)
		response.Error(c, http.StatusBadRequest, "invalid EventBridge notification format")
		return
	}

	h.logger.Info("received AWS event",
		"detail_type", event.DetailType,
		"source", event.Source,
		"account", event.Account,
		"region", event.Region,
	)

	// Process the event based on type
	if err := h.processAWSEvent(c.Request.Context(), &event); err != nil {
		h.logger.Error("failed to process AWS event", "error", err)
		response.Error(c, http.StatusInternalServerError, "failed to process event")
		return
	}

	response.Success(c, gin.H{"message": "event processed successfully"})
}

func (h *WebhookHandler) processAWSEvent(ctx context.Context, event *AWSEventBridgeNotification) error {
	// Determine the cloud account based on the AWS account ID
	// In a real implementation, you would look up the cloud_account by external_id (AWS account ID)
	// For now, we'll trigger a sync for the relevant account

	switch event.DetailType {
	case "EC2 Instance State-change Notification":
		return h.handleEC2StateChange(ctx, event)
	case "AWS API Call via CloudTrail":
		return h.handleCloudTrailEvent(ctx, event)
	default:
		h.logger.Info("unhandled event type", "detail_type", event.DetailType)
		return nil
	}
}

func (h *WebhookHandler) handleEC2StateChange(ctx context.Context, event *AWSEventBridgeNotification) error {
	state, _ := event.Detail["state"].(string)
	instanceID, _ := event.Detail["instance-id"].(string)

	h.logger.Info("EC2 instance state change",
		"instance_id", instanceID,
		"state", state,
		"account", event.Account,
		"region", event.Region,
	)

	// In a real implementation, you would:
	// 1. Look up the cloud account by AWS account ID
	// 2. If state is "running", trigger a targeted sync for this instance
	// 3. If state is "terminated", mark the asset as deleted

	// For now, we just log it
	// Future enhancement: implement selective asset refresh
	return nil
}

func (h *WebhookHandler) handleCloudTrailEvent(ctx context.Context, event *AWSEventBridgeNotification) error {
	eventName, _ := event.Detail["eventName"].(string)

	h.logger.Info("CloudTrail event",
		"event_name", eventName,
		"account", event.Account,
		"region", event.Region,
	)

	// Handle specific CloudTrail events that indicate asset changes
	switch eventName {
	case "RunInstances", "TerminateInstances":
		// Trigger sync for the affected account
		return h.triggerAccountSync(ctx, event.Account)
	case "CreateLoadBalancer", "DeleteLoadBalancer":
		return h.triggerAccountSync(ctx, event.Account)
	case "CreateDBInstance", "DeleteDBInstance":
		return h.triggerAccountSync(ctx, event.Account)
	default:
		h.logger.Debug("ignoring CloudTrail event", "event_name", eventName)
		return nil
	}
}

func (h *WebhookHandler) triggerAccountSync(ctx context.Context, awsAccountID string) error {
	if h.cloudAcctSvc == nil {
		return errors.New("cloud account service not configured")
	}
	account, err := h.cloudAcctSvc.FindByExternalID(ctx, caasmmodel.CloudProviderAWS, awsAccountID)
	if err != nil {
		h.logger.Warn("no cloud account found for AWS account", "aws_account_id", awsAccountID, "error", err)
		return err
	}

	_, err = h.cloudAcctSvc.TriggerSyncWithPriority(ctx, account.ID, nil, queue.PriorityHigh)
	if err != nil {
		h.logger.Error("failed to enqueue high-priority sync", "aws_account_id", awsAccountID, "account_id", account.ID, "error", err)
		return err
	}
	h.logger.Info("enqueued high-priority sync for AWS account", "aws_account_id", awsAccountID, "account_id", account.ID)
	return nil
}
