package webhook

import (
	"fmt"
	"net/url"
	"strings"

	clierrors "github.com/gitlink-org/gitlink-cli/internal/errors"
	"github.com/gitlink-org/gitlink-cli/internal/output"
	"github.com/gitlink-org/gitlink-cli/shortcuts/common"
)

// 支持的Webhook事件类型
var supportedEvents = []string{
	"push",
	"pull_request",
	"issue",
	"issue_assign",
	"issue_comment",
	"pull_request_assign",
	"pull_request_comment",
	"merge_request",
	"repository",
	"branch",
	"tag",
}

func isEventSupported(event string) bool {
	for _, supported := range supportedEvents {
		if event == supported {
			return true
		}
	}
	return false
}

func parseEvents(eventsStr string) []string {
	if eventsStr == "" {
		return []string{"push"} // 默认事件
	}
	events := strings.Split(eventsStr, ",")
	var validEvents []string
	for _, event := range events {
		event = strings.TrimSpace(event)
		if isEventSupported(event) {
			validEvents = append(validEvents, event)
		}
	}
	return validEvents
}

// webhookRepoPath returns the webhook API path prefix: /v1/{owner}/{repo}
// Note: BaseURL already includes /api prefix
func webhookRepoPath(ctx *common.RuntimeContext) string {
	return fmt.Sprintf("/v1/%s/%s", ctx.Owner, ctx.Repo)
}

func Shortcuts() []*common.Shortcut {
	return []*common.Shortcut{
		{
			Name:        "list",
			Description: "List all webhooks for a repository",
			Flags: []common.Flag{
				{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
				{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
			},
			Run: func(ctx *common.RuntimeContext) error {
				if err := ctx.ResolveOwnerRepo(); err != nil {
					return err
				}
				q := url.Values{}
				q.Set("page", ctx.Arg("page"))
				q.Set("limit", ctx.Arg("limit"))
				env, err := ctx.CallAPIWithQuery("GET", webhookRepoPath(ctx)+"/webhooks", q)
				if err != nil {
					return fmt.Errorf("获取 Webhook 列表失败: %w", err)
				}
				return ctx.Output(env)
			},
		},
		{
			Name:        "create",
			Description: "Create a new webhook",
			Flags: []common.Flag{
				{Name: "url", Short: "u", Usage: "Webhook callback URL", Required: true},
				{Name: "events", Short: "e", Usage: "Trigger events (comma-separated), e.g., push,pull_request,issue", Default: "push"},
				{Name: "active", Usage: "Webhook active status (true/false)", Default: "true"},
				{Name: "secret", Usage: "Webhook secret for HMAC verification"},
				{Name: "description", Short: "d", Usage: "Webhook description"},
			},
			Run: func(ctx *common.RuntimeContext) error {
				if err := ctx.ResolveOwnerRepo(); err != nil {
					return err
				}

				webhookURL, err := ctx.RequireArg("url", "--url https://example.com/hook")
				if err != nil {
					return err
				}

				events := parseEvents(ctx.Arg("events"))
				if len(events) == 0 {
					return clierrors.InputError(
						"no valid events specified",
						fmt.Sprintf("支持的事件类型: %s", strings.Join(supportedEvents, ", ")),
					)
				}

				payload := map[string]interface{}{
					"url":          webhookURL,
					"http_method":  "POST",
					"active":       true,
					"content_type": "json",
				}

				if len(events) > 0 {
					payload["events"] = events
				} else {
					payload["events"] = []string{"push"}
				}

				if secret := ctx.Arg("secret"); secret != "" {
					payload["secret"] = secret
				}

				if description := ctx.Arg("description"); description != "" {
					payload["description"] = description
				}

				env, err := ctx.CallAPI("POST", webhookRepoPath(ctx)+"/webhooks", payload)
				if err != nil {
					return fmt.Errorf("创建 Webhook 失败: %w", err)
				}
				return ctx.Output(env)
			},
		},
		{
			Name:        "update",
			Description: "Update an existing webhook",
			Flags: []common.Flag{
				{Name: "id", Short: "i", Usage: "Webhook ID", Required: true},
				{Name: "url", Short: "u", Usage: "Webhook callback URL"},
				{Name: "events", Short: "e", Usage: "Trigger events (comma-separated)"},
				{Name: "active", Usage: "Webhook active status (true/false)"},
				{Name: "content_type", Usage: "Content type (json/form)"},
				{Name: "secret", Usage: "Webhook secret for HMAC verification"},
				{Name: "description", Short: "d", Usage: "Webhook description"},
			},
			Run: func(ctx *common.RuntimeContext) error {
				if err := ctx.ResolveOwnerRepo(); err != nil {
					return err
				}

				webhookID, err := ctx.RequireArg("id", "--id 1")
				if err != nil {
					return err
				}

				payload := map[string]interface{}{
					"http_method":  "POST",
					"active":       true,
					"content_type": "json",
				}

				// 如果用户没有提供URL，获取当前webhook的URL
				webhookURL := ctx.Arg("url")
				if webhookURL == "" {
					getEnv, err := ctx.CallAPI("GET", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
					if err != nil {
						return fmt.Errorf("获取 Webhook 当前信息失败: %w", err)
					}
					webhookData, ok := getEnv.Data.(map[string]interface{})
					if !ok {
						return fmt.Errorf("failed to parse webhook data")
					}
					currentURL, ok := webhookData["url"].(string)
					if !ok || currentURL == "" {
						return fmt.Errorf("failed to get current webhook URL")
					}
					webhookURL = currentURL
				}
				payload["url"] = webhookURL

				if events := ctx.Arg("events"); events != "" {
					validEvents := parseEvents(events)
					if len(validEvents) == 0 {
						return clierrors.InputError(
							"no valid events specified",
							fmt.Sprintf("支持的事件类型: %s", strings.Join(supportedEvents, ", ")),
						)
					}
					payload["events"] = validEvents
				}


				if contentType := ctx.Arg("content_type"); contentType != "" {
					payload["content_type"] = contentType
				}

				if secret := ctx.Arg("secret"); secret != "" {
					payload["secret"] = secret
				}

				if description := ctx.Arg("description"); description != "" {
					payload["description"] = description
				}


				env, err := ctx.CallAPI("PUT", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), payload)
				if err != nil {
					return fmt.Errorf("更新 Webhook 失败: %w", err)
				}
				return ctx.Output(env)
			},
		},
		{
			Name:        "delete",
			Description: "Delete a webhook",
			Flags: []common.Flag{
				{Name: "id", Short: "i", Usage: "Webhook ID", Required: true},
			},
			Run: func(ctx *common.RuntimeContext) error {
				if err := ctx.ResolveOwnerRepo(); err != nil {
					return err
				}

				webhookID, err := ctx.RequireArg("id", "--id 1")
				if err != nil {
					return err
				}

				_, delErr := ctx.CallAPI("DELETE", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
				if delErr != nil {
					// 验证是否真的删除成功（类似release的处理）
					_, viewErr := ctx.CallAPI("GET", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
					if viewErr != nil {
						// Webhook不存在了，说明删除成功
						return ctx.Output(output.SuccessEnvelope(map[string]interface{}{
							"message": "Webhook deleted successfully",
						}, nil))
					}
					return fmt.Errorf("删除 Webhook 失败: %w", delErr)
				}
				return ctx.Output(output.SuccessEnvelope(map[string]interface{}{
					"message": "Webhook deleted successfully",
				}, nil))
			},
		},
		{
			Name:        "test",
			Description: "Test a webhook delivery (send a ping event)",
			Flags: []common.Flag{
				{Name: "id", Short: "i", Usage: "Webhook ID", Required: true},
				{Name: "event", Short: "e", Usage: "Event type to test (default: push)", Default: "push"},
			},
			Run: func(ctx *common.RuntimeContext) error {
				if err := ctx.ResolveOwnerRepo(); err != nil {
					return err
				}

				webhookID, err := ctx.RequireArg("id", "--id 1")
				if err != nil {
					return err
				}

				eventType := ctx.Arg("event")
				if !isEventSupported(eventType) {
					return clierrors.InputError(
						fmt.Sprintf("unsupported event type: %s", eventType),
						fmt.Sprintf("支持的事件类型: %s", strings.Join(supportedEvents, ", ")),
					)
				}

				env, err := ctx.CallAPI("POST", fmt.Sprintf("%s/webhooks/%s/tests", webhookRepoPath(ctx), webhookID), nil)
				if err != nil {
					return fmt.Errorf("测试 Webhook 失败: %w", err)
				}
				return ctx.Output(env)
			},
		},
		{
			Name:        "info",
			Description: "Show webhook details",
			Flags: []common.Flag{
				{Name: "id", Short: "i", Usage: "Webhook ID", Required: true},
			},
			Run: func(ctx *common.RuntimeContext) error {
				if err := ctx.ResolveOwnerRepo(); err != nil {
					return err
				}

				webhookID, err := ctx.RequireArg("id", "--id 1")
				if err != nil {
					return err
				}

				env, err := ctx.CallAPI("GET", fmt.Sprintf("%s/webhooks/%s", webhookRepoPath(ctx), webhookID), nil)
				if err != nil {
					return fmt.Errorf("查看 Webhook 详情失败: %w", err)
				}
				return ctx.Output(env)
			},
		},
		{
			Name: "events",
			Description: "List all supported event types for webhooks",
			Run: func(ctx *common.RuntimeContext) error {
				eventInfo := make([]map[string]interface{}, 0)
				for _, event := range supportedEvents {
					eventInfo = append(eventInfo, map[string]interface{}{
						"event":      event,
						"supported":  true,
						"description": getEventDescription(event),
					})
				}
				return ctx.Output(output.SuccessEnvelope(eventInfo, nil))
			},
		},
	}
}

func getEventDescription(event string) string {
	descriptions := map[string]string{
		"push":                "Code push events",
		"pull_request":        "Pull request events",
		"issue":               "Issue events",
		"issue_assign":        "Issue assignment events",
		"issue_comment":       "Issue comment events",
		"pull_request_assign": "Pull request assignment events",
		"pull_request_comment":"Pull request comment events",
		"merge_request":       "Merge request events",
		"repository":          "Repository events",
		"branch":              "Branch creation/deletion events",
		"tag":                 "Tag creation/deletion events",
	}
	if desc, ok := descriptions[event]; ok {
		return desc
	}
	return "Custom event"
}
