package GCP_CLOUD_FUNCTIONS

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/cloudevents/sdk-go/v2/event"
)

// MessagePublishedData 定义 Pub/Sub 推送过来的 CloudEvent 数据结构
type MessagePublishedData struct {
	Message PubSubMessage `json:"message"`
}

type PubSubMessage struct {
	Data []byte `json:"data"`
}

// SCCNotification 定义 SCC JSON 结构
type SCCNotification struct {
	Finding  Finding   `json:"finding"`
	Resource *Resource `json:"resource,omitempty"`
}

type Resource struct {
	Name        string `json:"name"`
	DisplayName string `json:"displayName"`
	Type        string `json:"type"`
}

type Finding struct {
	Name             string      `json:"name"`
	Category         string      `json:"category"`
	Description      string      `json:"description"`
	Severity         string      `json:"severity"`
	EventTime        string      `json:"eventTime"`
	ResourceName     string      `json:"resourceName"`
	ExternalURI      string      `json:"externalUri"`
	SourceProperties interface{} `json:"sourceProperties"`
}

type LarkMessage struct {
	MsgType string      `json:"msg_type"`
	Card    interface{} `json:"card"`
}

type ParsedResource struct {
	ProjectID   string
	Location    string
	Type        string
	ShortName   string
	FullDisplay string
}

func StartAlertHandler(ctx context.Context, e event.Event) error {
	var msgData MessagePublishedData
	if err := e.DataAs(&msgData); err != nil {
		return fmt.Errorf("event.DataAs: %v", err)
	}

	var sccPayload SCCNotification
	if err := json.Unmarshal(msgData.Message.Data, &sccPayload); err != nil {
		return fmt.Errorf("json.Unmarshal scc payload: %v", err)
	}

	finding := sccPayload.Finding
	if finding.Name == "" {
		log.Println("No finding name found, skipping.")
		return nil
	}

	propsMap := normalizeSourceProperties(finding.SourceProperties)
	log.Printf("Processing Alert: %s - %s", finding.Category, finding.Severity)

	displayTime := finding.EventTime
	if t, err := time.Parse(time.RFC3339, finding.EventTime); err == nil {
		displayTime = t.Format("2006-01-02 15:04:05 UTC")
	}

	resourceDisplayName := ""
	if sccPayload.Resource != nil {
		resourceDisplayName = sccPayload.Resource.DisplayName
	}
	resInfo := parseResourceString(finding.ResourceName, propsMap, resourceDisplayName)

	explanation := ""
	recommendation := ""

	if val, ok := propsMap["Explanation"].(string); ok {
		explanation = val
	} else if val, ok := propsMap["explanation"].(string); ok {
		explanation = val
	}

	if val, ok := propsMap["Recommendation"].(string); ok {
		recommendation = val
	} else if val, ok := propsMap["recommendation"].(string); ok {
		recommendation = val
	} else if val, ok := propsMap["next_steps"].(string); ok {
		recommendation = val
	}

	webhookURL := os.Getenv("LARK_WEBHOOK_URL")
	if webhookURL == "" {
		return fmt.Errorf("LARK_WEBHOOK_URL env var not set")
	}

	err := sendToLark(webhookURL, finding, displayTime, resInfo, explanation, recommendation)
	if err != nil {
		return fmt.Errorf("failed to send to lark: %v", err)
	}

	return nil
}

func normalizeSourceProperties(input interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	if input == nil {
		return result
	}
	if m, ok := input.(map[string]interface{}); ok {
		return m
	}
	if list, ok := input.([]interface{}); ok {
		for _, item := range list {
			if kv, ok := item.(map[string]interface{}); ok {
				var k string
				var v interface{}
				if keyVal, exists := kv["key"]; exists {
					k = fmt.Sprintf("%v", keyVal)
				}
				if valVal, exists := kv["value"]; exists {
					v = valVal
				}
				if k != "" {
					result[k] = v
				}
			}
		}
	}
	return result
}

// 核心修改逻辑在这个函数里
func parseResourceString(fullPath string, props map[string]interface{}, directDisplayName string) ParsedResource {
	r := ParsedResource{
		ProjectID: "Unknown",
		Location:  "Global",
		Type:      "Resource",
		ShortName: "Unknown",
	}

	// 1. 基础解析
	trimPath := fullPath
	if strings.HasPrefix(fullPath, "//") {
		parts := strings.SplitN(fullPath, "/", 4)
		if len(parts) >= 4 {
			trimPath = parts[3] // 去掉 API 前缀，保留 projects/xxx/...
		}
	}
	segments := strings.Split(trimPath, "/")

	for i := 0; i < len(segments)-1; i++ {
		key := segments[i]
		val := segments[i+1]
		switch key {
		case "projects":
			r.ProjectID = val
		case "zones", "locations", "regions":
			r.Location = val
		}
	}

	if len(segments) >= 2 {
		r.Type = segments[len(segments)-2]
		r.ShortName = segments[len(segments)-1]
	} else if len(segments) == 1 {
		r.ShortName = segments[0]
	}
	if r.Type == "projects" {
		r.ShortName = r.ProjectID
		r.Type = "Project"
	}

	// 2. 寻找更好听的名字
	if directDisplayName != "" {
		r.ShortName = directDisplayName
	} else {
		betterName := ""
		candidateKeys := []string{"resourceName", "resourceDisplayName", "email", "principalEmail"}
		for _, key := range candidateKeys {
			if val, ok := props[key].(string); ok && val != "" {
				if strings.Contains(val, "@") {
					betterName = val
					break
				}
				if isNumeric(r.ShortName) && !isNumeric(val) && !strings.Contains(val, "/") {
					betterName = val
				}
				// 如果找到的是个完整路径（包含 projects/），也暂存下来
				if strings.HasPrefix(val, "//") || strings.HasPrefix(val, "projects/") {
					betterName = val
				}
			}
		}
		if betterName != "" {
			r.ShortName = betterName
		}
	}

	// 3. 构造 FullDisplay (修复了重复拼接的问题)

	// 清理一下 ShortName，防止它带着 //xxx.googleapis.com/
	finalName := r.ShortName
	if strings.HasPrefix(finalName, "//") {
		parts := strings.SplitN(finalName, "/", 4)
		if len(parts) >= 4 {
			finalName = parts[3]
		}
	}

	// 关键判断：如果 finalName 已经包含了 "projects/"，说明它已经是全路径了，直接用！
	// 否则，才进行手动拼接。
	if strings.HasPrefix(finalName, "projects/") {
		r.FullDisplay = finalName
	} else if r.ProjectID != "Unknown" && r.Type != "Project" {
		r.FullDisplay = fmt.Sprintf("projects/%s/%s/%s", r.ProjectID, r.Type, finalName)
	} else {
		r.FullDisplay = finalName
	}

	return r
}

func isNumeric(s string) bool {
	for _, c := range s {
		if c < '0' || c > '9' {
			return false
		}
	}
	return len(s) > 0
}

func sendToLark(url string, f Finding, timeStr string, res ParsedResource, explanation string, recommendation string) error {
	headerColor := "orange"
	severityEmoji := "🟠"

	switch f.Severity {
	case "CRITICAL":
		headerColor = "red"
		severityEmoji = "🔴"
	case "HIGH":
		headerColor = "carmine"
		severityEmoji = "🟠"
	case "MEDIUM":
		headerColor = "orange"
		severityEmoji = "🟡"
	case "LOW":
		headerColor = "blue"
		severityEmoji = "🔵"
		return nil // Low severity, no need to notify Lark
	}

	elements := []interface{}{}

	fieldsRow1 := []interface{}{
		map[string]interface{}{
			"is_short": true,
			"text": map[string]interface{}{
				"tag":     "lark_md",
				"content": fmt.Sprintf("**Severity:**\n%s %s", severityEmoji, f.Severity),
			},
		},
		map[string]interface{}{
			"is_short": true,
			"text": map[string]interface{}{
				"tag":     "lark_md",
				"content": fmt.Sprintf("**Time:**\n%s", timeStr),
			},
		},
	}
	elements = append(elements, map[string]interface{}{
		"tag":    "div",
		"fields": fieldsRow1,
	})

	fieldsRow2 := []interface{}{
		map[string]interface{}{
			"is_short": true,
			"text": map[string]interface{}{
				"tag":     "lark_md",
				"content": fmt.Sprintf("**Project:**\n%s", res.ProjectID),
			},
		},
		map[string]interface{}{
			"is_short": true,
			"text": map[string]interface{}{
				"tag":     "lark_md",
				"content": fmt.Sprintf("**Location:**\n%s", res.Location),
			},
		},
	}
	elements = append(elements, map[string]interface{}{
		"tag":    "div",
		"fields": fieldsRow2,
	})

	elements = append(elements, map[string]interface{}{
		"tag": "div",
		"text": map[string]interface{}{
			"tag":     "lark_md",
			"content": fmt.Sprintf("**Resource:**\n`%s`", res.FullDisplay),
		},
	})

	elements = append(elements, map[string]interface{}{"tag": "hr"})

	infoText := ""
	if f.Description != "" {
		infoText += fmt.Sprintf("**Description:**\n%s\n\n", f.Description)
	}
	if explanation != "" {
		infoText += fmt.Sprintf("**Analysis:**\n%s\n\n", explanation)
	}
	if recommendation != "" {
		infoText += fmt.Sprintf("**Recommendation:**\n%s", recommendation)
	}
	if infoText == "" {
		infoText = "No additional details provided by SCC."
	}

	elements = append(elements, map[string]interface{}{
		"tag": "div",
		"text": map[string]interface{}{
			"tag":     "lark_md",
			"content": infoText,
		},
	})

	link := f.ExternalURI
	if link == "" {
		link = "https://console.cloud.google.com/security/command-center/findings"
	}

	elements = append(elements, map[string]interface{}{
		"tag": "action",
		"actions": []interface{}{
			map[string]interface{}{
				"tag": "button",
				"text": map[string]interface{}{
					"tag":     "plain_text",
					"content": "View in SCC Console",
				},
				"type": "primary",
				"url":  link,
			},
		},
	})

	cardContent := map[string]interface{}{
		"config": map[string]interface{}{"wide_screen_mode": true},
		"header": map[string]interface{}{
			"template": headerColor,
			"title": map[string]interface{}{
				"tag":     "plain_text",
				"content": fmt.Sprintf("🚨 SCC Alert: %s", f.Category),
			},
		},
		"elements": elements,
	}

	msg := LarkMessage{
		MsgType: "interactive",
		Card:    cardContent,
	}

	payload, _ := json.Marshal(msg)
	resp, err := http.Post(url, "application/json", strings.NewReader(string(payload)))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("lark api status: %d", resp.StatusCode)
	}
	return nil
}
