// Package zoraxy_plugin provides the Zoraxy plugin interface types and helpers.
// This is a vendored copy from github.com/tobychui/zoraxy/src/mod/plugins/zoraxy_plugin/
// Licensed under LGPL.
package zoraxy_plugin

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
)

type PluginType int

const (
	PluginType_Router    PluginType = 0
	PluginType_Utilities PluginType = 1
)

type StaticCaptureRule struct {
	CapturePath string `json:"capture_path"`
}

type ControlStatusCode int

const (
	ControlStatusCode_CAPTURED  ControlStatusCode = 280
	ControlStatusCode_UNHANDLED ControlStatusCode = 284
	ControlStatusCode_ERROR     ControlStatusCode = 580
)

type SubscriptionEvent struct {
	EventName   string `json:"event_name"`
	EventSource string `json:"event_source"`
	Payload     string `json:"payload"`
}

type RuntimeConstantValue struct {
	ZoraxyVersion    string `json:"zoraxy_version"`
	ZoraxyUUID       string `json:"zoraxy_uuid"`
	DevelopmentBuild bool   `json:"development_build"`
}

type PermittedAPIEndpoint struct {
	Method   string `json:"method"`
	Endpoint string `json:"endpoint"`
	Reason   string `json:"reason"`
}

type IntroSpect struct {
	ID            string     `json:"id"`
	Name          string     `json:"name"`
	Author        string     `json:"author"`
	AuthorContact string     `json:"author_contact"`
	Description   string     `json:"description"`
	URL           string     `json:"url"`
	Type          PluginType `json:"type"`
	VersionMajor  int        `json:"version_major"`
	VersionMinor  int        `json:"version_minor"`
	VersionPatch  int        `json:"version_patch"`

	StaticCapturePaths   []StaticCaptureRule `json:"static_capture_paths"`
	StaticCaptureIngress string              `json:"static_capture_ingress"`

	DynamicCaptureSniff   string `json:"dynamic_capture_sniff"`
	DynamicCaptureIngress string `json:"dynamic_capture_ingress"`

	UIPath string `json:"ui_path"`

	SubscriptionPath    string            `json:"subscription_path"`
	SubscriptionsEvents map[string]string `json:"subscriptions_events"`

	PermittedAPIEndpoints []PermittedAPIEndpoint `json:"permitted_api_endpoints"`
}

type ConfigureSpec struct {
	Port         int                  `json:"port"`
	RuntimeConst RuntimeConstantValue `json:"runtime_const"`
	APIKey       string               `json:"api_key,omitempty"`
	ZoraxyPort   int                  `json:"zoraxy_port,omitempty"`
}

// ServeIntroSpect checks for -introspect flag and prints the spec as JSON, then exits.
func ServeIntroSpect(pluginSpect *IntroSpect) {
	if len(os.Args) > 1 && os.Args[1] == "-introspect" {
		jsonData, _ := json.MarshalIndent(pluginSpect, "", " ")
		fmt.Println(string(jsonData))
		os.Exit(0)
	}
}

// RecvConfigureSpec reads the -configure flag from command line args.
func RecvConfigureSpec() (*ConfigureSpec, error) {
	for i, arg := range os.Args {
		if strings.HasPrefix(arg, "-configure=") {
			var spec ConfigureSpec
			if err := json.Unmarshal([]byte(arg[11:]), &spec); err != nil {
				return nil, err
			}
			return &spec, nil
		} else if arg == "-configure" {
			var spec ConfigureSpec
			if len(os.Args) > i+1 {
				if err := json.Unmarshal([]byte(os.Args[i+1]), &spec); err != nil {
					return nil, err
				}
				return &spec, nil
			}
			return nil, fmt.Errorf("no argument after -configure flag")
		}
	}
	return nil, fmt.Errorf("-configure flag not found")
}

// ServeAndRecvSpec serves introspection and returns config in one call.
func ServeAndRecvSpec(pluginSpect *IntroSpect) (*ConfigureSpec, error) {
	ServeIntroSpect(pluginSpect)
	return RecvConfigureSpec()
}
