package main

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"strings"

	"enclave/internal/keybase"
	"enclave/internal/state"
	"enclave/internal/types"

	"github.com/extism/go-pdk"
)

func main() { state.Default() }

//go:wasmexport ping
func ping() int32 {
	pdk.Log(pdk.LogInfo, "ping: received request")

	var input types.PingInput
	if err := pdk.InputJSON(&input); err != nil {
		output := types.PingOutput{
			Success: false,
			Message: fmt.Sprintf("failed to parse input: %s", err),
		}
		pdk.OutputJSON(output)
		return 0
	}

	output := types.PingOutput{
		Success: true,
		Message: "pong",
		Echo:    input.Message,
	}

	if err := pdk.OutputJSON(output); err != nil {
		pdk.Log(pdk.LogError, fmt.Sprintf("ping: failed to output: %s", err))
		return 1
	}

	pdk.Log(pdk.LogInfo, fmt.Sprintf("ping: responded with echo=%s", input.Message))
	return 0
}

//go:wasmexport generate
func generate() int32 {
	pdk.Log(pdk.LogInfo, "generate: starting database initialization")

	var input types.GenerateInput
	if err := pdk.InputJSON(&input); err != nil {
		pdk.SetError(fmt.Errorf("generate: failed to parse input: %w", err))
		return 1
	}

	if input.Credential == "" {
		pdk.SetError(errors.New("generate: credential is required"))
		return 1
	}

	credentialBytes, err := base64.StdEncoding.DecodeString(input.Credential)
	if err != nil {
		pdk.SetError(fmt.Errorf("generate: invalid base64 credential: %w", err))
		return 1
	}

	did, err := initializeDatabase(credentialBytes)
	if err != nil {
		pdk.SetError(fmt.Errorf("generate: failed to initialize database: %w", err))
		return 1
	}

	state.SetInitialized(true)
	state.SetDID(did)

	dbBytes, err := serializeDatabase()
	if err != nil {
		pdk.SetError(fmt.Errorf("generate: failed to serialize database: %w", err))
		return 1
	}

	output := types.GenerateOutput{
		DID:      did,
		Database: dbBytes,
	}

	if err := pdk.OutputJSON(output); err != nil {
		pdk.SetError(fmt.Errorf("generate: failed to output result: %w", err))
		return 1
	}

	pdk.Log(pdk.LogInfo, fmt.Sprintf("generate: created DID %s", did))
	return 0
}

//go:wasmexport load
func load() int32 {
	pdk.Log(pdk.LogInfo, "load: loading database from buffer")

	var input types.LoadInput
	if err := pdk.InputJSON(&input); err != nil {
		pdk.SetError(fmt.Errorf("load: failed to parse input: %w", err))
		return 1
	}

	if len(input.Database) == 0 {
		pdk.SetError(errors.New("load: database buffer is required"))
		return 1
	}

	did, err := loadDatabase(input.Database)
	if err != nil {
		output := types.LoadOutput{
			Success: false,
			Error:   err.Error(),
		}
		pdk.OutputJSON(output)
		return 1
	}

	state.SetInitialized(true)
	state.SetDID(did)

	output := types.LoadOutput{
		Success: true,
		DID:     did,
	}

	if err := pdk.OutputJSON(output); err != nil {
		pdk.SetError(fmt.Errorf("load: failed to output result: %w", err))
		return 1
	}

	pdk.Log(pdk.LogInfo, fmt.Sprintf("load: loaded database for DID %s", did))
	return 0
}

//go:wasmexport exec
func exec() int32 {
	pdk.Log(pdk.LogInfo, "exec: executing action")

	if !state.IsInitialized() {
		output := types.ExecOutput{Success: false, Error: "database not initialized, call generate or load first"}
		pdk.OutputJSON(output)
		return 0
	}

	var input types.ExecInput
	if err := pdk.InputJSON(&input); err != nil {
		output := types.ExecOutput{Success: false, Error: fmt.Sprintf("failed to parse input: %s", err)}
		pdk.OutputJSON(output)
		return 0
	}

	if input.Filter == "" {
		output := types.ExecOutput{Success: false, Error: "filter is required"}
		pdk.OutputJSON(output)
		return 0
	}

	params, err := parseFilter(input.Filter)
	if err != nil {
		output := types.ExecOutput{Success: false, Error: fmt.Sprintf("invalid filter: %s", err)}
		pdk.OutputJSON(output)
		return 0
	}

	if input.Token != "" {
		if err := validateUCAN(input.Token, params); err != nil {
			output := types.ExecOutput{
				Success: false,
				Error:   fmt.Sprintf("authorization failed: %s", err.Error()),
			}
			pdk.OutputJSON(output)
			return 1
		}
	}

	result, err := executeAction(params)
	if err != nil {
		output := types.ExecOutput{
			Success: false,
			Error:   err.Error(),
		}
		pdk.OutputJSON(output)
		return 1
	}

	output := types.ExecOutput{
		Success: true,
		Result:  result,
	}

	pdk.OutputJSON(output)
	pdk.Log(pdk.LogInfo, fmt.Sprintf("exec: completed %s on %s", params.Action, params.Resource))
	return 0
}

//go:wasmexport query
func query() int32 {
	pdk.Log(pdk.LogInfo, "query: resolving DID document")

	if !state.IsInitialized() {
		pdk.SetError(errors.New("database not initialized, call generate or load first"))
		return 1
	}

	var input types.QueryInput
	if err := pdk.InputJSON(&input); err != nil {
		pdk.SetError(fmt.Errorf("query: failed to parse input: %w", err))
		return 1
	}

	if input.DID == "" {
		input.DID = state.GetDID()
	}

	if !strings.HasPrefix(input.DID, "did:") {
		pdk.SetError(errors.New("query: invalid DID format"))
		return 1
	}

	output, err := resolveDID(input.DID)
	if err != nil {
		pdk.SetError(fmt.Errorf("query: failed to resolve DID: %w", err))
		return 1
	}

	if err := pdk.OutputJSON(output); err != nil {
		pdk.SetError(fmt.Errorf("query: failed to output result: %w", err))
		return 1
	}

	pdk.Log(pdk.LogInfo, fmt.Sprintf("query: resolved DID %s", input.DID))
	return 0
}

func initializeDatabase(credentialBytes []byte) (string, error) {
	kb, err := keybase.Open()
	if err != nil {
		return "", fmt.Errorf("open database: %w", err)
	}

	ctx := context.Background()
	did, err := kb.Initialize(ctx, credentialBytes)
	if err != nil {
		return "", fmt.Errorf("initialize: %w", err)
	}

	pdk.Log(pdk.LogDebug, "initializeDatabase: created schema and initial records")
	return did, nil
}

func serializeDatabase() ([]byte, error) {
	kb := keybase.Get()
	if kb == nil {
		return nil, errors.New("database not initialized")
	}
	return kb.Serialize()
}

func loadDatabase(data []byte) (string, error) {
	if len(data) < 10 {
		return "", errors.New("invalid database format")
	}

	kb, err := keybase.Open()
	if err != nil {
		return "", fmt.Errorf("open database: %w", err)
	}

	ctx := context.Background()
	did, err := kb.Load(ctx, data)
	if err != nil {
		return "", fmt.Errorf("load DID: %w", err)
	}

	pdk.Log(pdk.LogDebug, "loadDatabase: database loaded successfully")
	return did, nil
}

func parseFilter(filter string) (*types.FilterParams, error) {
	params := &types.FilterParams{}
	parts := strings.FieldsSeq(filter)

	for part := range parts {
		kv := strings.SplitN(part, ":", 2)
		if len(kv) != 2 {
			continue
		}

		key, value := kv[0], kv[1]
		switch key {
		case "resource":
			params.Resource = value
		case "action":
			params.Action = value
		case "subject":
			params.Subject = value
		}
	}

	if params.Resource == "" {
		return nil, errors.New("resource is required")
	}
	if params.Action == "" {
		return nil, errors.New("action is required")
	}

	return params, nil
}

func validateUCAN(token string, params *types.FilterParams) error {
	if token == "" {
		return errors.New("token is required")
	}

	parts := strings.Split(token, ".")
	if len(parts) != 3 {
		return errors.New("invalid token format: expected JWT with 3 parts")
	}

	payload, err := base64.RawURLEncoding.DecodeString(parts[1])
	if err != nil {
		return fmt.Errorf("invalid token payload: %w", err)
	}

	var claims map[string]any
	if err := json.Unmarshal(payload, &claims); err != nil {
		return fmt.Errorf("invalid token claims: %w", err)
	}

	if exp, ok := claims["exp"].(float64); ok {
		if int64(exp) < currentUnixTime() {
			return errors.New("token has expired")
		}
	}

	if nbf, ok := claims["nbf"].(float64); ok {
		if int64(nbf) > currentUnixTime() {
			return errors.New("token is not yet valid")
		}
	}

	if aud, ok := claims["aud"].(string); ok {
		currentDID := state.GetDID()
		if currentDID != "" && aud != currentDID {
			pdk.Log(pdk.LogDebug, fmt.Sprintf("validateUCAN: audience mismatch, expected %s got %s", currentDID, aud))
		}
	}

	if att, ok := claims["att"].([]any); ok {
		if !checkAttenuations(att, params.Resource, params.Action) {
			return fmt.Errorf("token does not grant capability for %s:%s", params.Resource, params.Action)
		}
	}

	am, err := keybase.NewActionManager()
	if err == nil {
		if cid, ok := claims["cid"].(string); ok {
			ctx := context.Background()
			revoked, err := am.IsUCANRevoked(ctx, cid)
			if err == nil && revoked {
				return errors.New("token has been revoked")
			}
		}
	}

	pdk.Log(pdk.LogDebug, fmt.Sprintf("validateUCAN: validated token for %s:%s", params.Resource, params.Action))
	return nil
}

func currentUnixTime() int64 {
	return 0
}

func checkAttenuations(attenuations []any, resource, action string) bool {
	for _, att := range attenuations {
		attMap, ok := att.(map[string]any)
		if !ok {
			continue
		}

		with, ok := attMap["with"].(string)
		if !ok {
			continue
		}

		if !matchResource(with, resource) {
			continue
		}

		can := attMap["can"]
		if canStr, ok := can.(string); ok {
			if canStr == "*" || canStr == action {
				return true
			}
		} else if canSlice, ok := can.([]any); ok {
			for _, c := range canSlice {
				if cStr, ok := c.(string); ok {
					if cStr == "*" || cStr == action {
						return true
					}
				}
			}
		}
	}
	return false
}

func matchResource(pattern, resource string) bool {
	if pattern == resource {
		return true
	}

	if strings.HasSuffix(pattern, "/*") {
		prefix := strings.TrimSuffix(pattern, "/*")
		return strings.HasPrefix(resource, prefix)
	}

	if strings.Contains(pattern, "://") {
		parts := strings.SplitN(pattern, "://", 2)
		if len(parts) == 2 && parts[1] == resource {
			return true
		}
	}

	return false
}

func executeAction(params *types.FilterParams) (json.RawMessage, error) {
	switch params.Resource {
	case "accounts":
		return executeAccountAction(params)
	case "credentials":
		return executeCredentialAction(params)
	case "sessions":
		return executeSessionAction(params)
	case "grants":
		return executeGrantAction(params)
	case "key_shares":
		return executeKeyShareAction(params)
	case "ucans":
		return executeUCANAction(params)
	case "delegations":
		return executeDelegationAction(params)
	case "verification_methods":
		return executeVerificationMethodAction(params)
	case "services":
		return executeServiceAction(params)
	default:
		return nil, fmt.Errorf("unknown resource: %s", params.Resource)
	}
}

func executeAccountAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		accounts, err := am.ListAccounts(ctx)
		if err != nil {
			return nil, fmt.Errorf("list accounts: %w", err)
		}
		return json.Marshal(accounts)
	case "get":
		if params.Subject == "" {
			return nil, errors.New("subject (address) required for get action")
		}
		account, err := am.GetAccountByAddress(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("get account: %w", err)
		}
		return json.Marshal(account)
	case "balances":
		return fetchAccountBalances(params.Subject)
	case "sign":
		return json.Marshal(map[string]string{"signature": "placeholder"})
	default:
		return nil, fmt.Errorf("unknown action for accounts: %s", params.Action)
	}
}

func fetchAccountBalances(address string) (json.RawMessage, error) {
	if address == "" {
		address = state.GetDID()
	}

	apiBase, ok := state.GetConfig("api_endpoint")
	if !ok {
		apiBase = "https://api.sonr.io"
	}

	url := fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", apiBase, address)
	pdk.Log(pdk.LogInfo, fmt.Sprintf("fetchAccountBalances: GET %s", url))

	req := pdk.NewHTTPRequest(pdk.MethodGet, url)
	req.SetHeader("Accept", "application/json")

	res := req.Send()
	status := res.Status()

	if status < 200 || status >= 300 {
		pdk.Log(pdk.LogError, fmt.Sprintf("fetchAccountBalances: HTTP %d", status))
		return json.Marshal(map[string]any{
			"error":   "failed to fetch balances",
			"status":  status,
			"address": address,
		})
	}

	body := res.Body()
	pdk.Log(pdk.LogDebug, fmt.Sprintf("fetchAccountBalances: received %d bytes", len(body)))

	return body, nil
}

func executeCredentialAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		credentials, err := am.ListCredentials(ctx)
		if err != nil {
			return nil, fmt.Errorf("list credentials: %w", err)
		}
		return json.Marshal(credentials)
	case "get":
		if params.Subject == "" {
			return nil, errors.New("subject (credential_id) required for get action")
		}
		credential, err := am.GetCredentialByID(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("get credential: %w", err)
		}
		return json.Marshal(credential)
	default:
		return nil, fmt.Errorf("unknown action for credentials: %s", params.Action)
	}
}

func executeSessionAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		sessions, err := am.ListSessions(ctx)
		if err != nil {
			return nil, fmt.Errorf("list sessions: %w", err)
		}
		return json.Marshal(sessions)
	case "revoke":
		if params.Subject == "" {
			return nil, errors.New("subject (session_id) required for revoke action")
		}
		if err := am.RevokeSession(ctx, params.Subject); err != nil {
			return nil, fmt.Errorf("revoke session: %w", err)
		}
		return json.Marshal(map[string]bool{"revoked": true})
	default:
		return nil, fmt.Errorf("unknown action for sessions: %s", params.Action)
	}
}

func executeGrantAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		grants, err := am.ListGrants(ctx)
		if err != nil {
			return nil, fmt.Errorf("list grants: %w", err)
		}
		return json.Marshal(grants)
	case "revoke":
		if params.Subject == "" {
			return nil, errors.New("subject (grant_id) required for revoke action")
		}
		var grantID int64
		if _, err := fmt.Sscanf(params.Subject, "%d", &grantID); err != nil {
			return nil, fmt.Errorf("invalid grant_id: %w", err)
		}
		if err := am.RevokeGrant(ctx, grantID); err != nil {
			return nil, fmt.Errorf("revoke grant: %w", err)
		}
		return json.Marshal(map[string]bool{"revoked": true})
	default:
		return nil, fmt.Errorf("unknown action for grants: %s", params.Action)
	}
}

func executeKeyShareAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		shares, err := am.ListKeyShares(ctx)
		if err != nil {
			return nil, fmt.Errorf("list key shares: %w", err)
		}
		return json.Marshal(shares)
	case "get":
		if params.Subject == "" {
			return nil, errors.New("subject (share_id) required for get action")
		}
		share, err := am.GetKeyShareByID(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("get key share: %w", err)
		}
		return json.Marshal(share)
	case "rotate":
		if params.Subject == "" {
			return nil, errors.New("subject (share_id) required for rotate action")
		}
		if err := am.RotateKeyShare(ctx, params.Subject); err != nil {
			return nil, fmt.Errorf("rotate key share: %w", err)
		}
		return json.Marshal(map[string]bool{"rotated": true})
	case "archive":
		if params.Subject == "" {
			return nil, errors.New("subject (share_id) required for archive action")
		}
		if err := am.ArchiveKeyShare(ctx, params.Subject); err != nil {
			return nil, fmt.Errorf("archive key share: %w", err)
		}
		return json.Marshal(map[string]bool{"archived": true})
	case "delete":
		if params.Subject == "" {
			return nil, errors.New("subject (share_id) required for delete action")
		}
		if err := am.DeleteKeyShare(ctx, params.Subject); err != nil {
			return nil, fmt.Errorf("delete key share: %w", err)
		}
		return json.Marshal(map[string]bool{"deleted": true})
	default:
		return nil, fmt.Errorf("unknown action for key_shares: %s", params.Action)
	}
}

func executeUCANAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		ucans, err := am.ListUCANs(ctx)
		if err != nil {
			return nil, fmt.Errorf("list ucans: %w", err)
		}
		return json.Marshal(ucans)
	case "get":
		if params.Subject == "" {
			return nil, errors.New("subject (cid) required for get action")
		}
		ucan, err := am.GetUCANByCID(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("get ucan: %w", err)
		}
		return json.Marshal(ucan)
	case "revoke":
		if params.Subject == "" {
			return nil, errors.New("subject (cid) required for revoke action")
		}
		if err := am.RevokeUCAN(ctx, params.Subject); err != nil {
			return nil, fmt.Errorf("revoke ucan: %w", err)
		}
		return json.Marshal(map[string]bool{"revoked": true})
	case "verify":
		if params.Subject == "" {
			return nil, errors.New("subject (cid) required for verify action")
		}
		revoked, err := am.IsUCANRevoked(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("check ucan: %w", err)
		}
		return json.Marshal(map[string]bool{"valid": !revoked, "revoked": revoked})
	case "cleanup":
		if err := am.CleanExpiredUCANs(ctx); err != nil {
			return nil, fmt.Errorf("cleanup ucans: %w", err)
		}
		return json.Marshal(map[string]bool{"cleaned": true})
	default:
		return nil, fmt.Errorf("unknown action for ucans: %s", params.Action)
	}
}

func executeDelegationAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		if params.Subject == "" {
			return nil, errors.New("subject (delegator or delegate DID) required for list action")
		}
		delegations, err := am.ListDelegationsByDelegator(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("list delegations: %w", err)
		}
		return json.Marshal(delegations)
	case "list_received":
		if params.Subject == "" {
			return nil, errors.New("subject (delegate DID) required for list_received action")
		}
		delegations, err := am.ListDelegationsByDelegate(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("list received delegations: %w", err)
		}
		return json.Marshal(delegations)
	case "list_resource":
		if params.Subject == "" {
			return nil, errors.New("subject (resource) required for list_resource action")
		}
		delegations, err := am.ListDelegationsForResource(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("list delegations for resource: %w", err)
		}
		return json.Marshal(delegations)
	case "chain":
		if params.Subject == "" {
			return nil, errors.New("subject (delegation_id) required for chain action")
		}
		var delegationID int64
		if _, err := fmt.Sscanf(params.Subject, "%d", &delegationID); err != nil {
			return nil, fmt.Errorf("invalid delegation_id: %w", err)
		}
		chain, err := am.GetDelegationChain(ctx, delegationID)
		if err != nil {
			return nil, fmt.Errorf("get delegation chain: %w", err)
		}
		return json.Marshal(chain)
	case "revoke":
		if params.Subject == "" {
			return nil, errors.New("subject (delegation_id) required for revoke action")
		}
		var delegationID int64
		if _, err := fmt.Sscanf(params.Subject, "%d", &delegationID); err != nil {
			return nil, fmt.Errorf("invalid delegation_id: %w", err)
		}
		if err := am.RevokeDelegation(ctx, delegationID); err != nil {
			return nil, fmt.Errorf("revoke delegation: %w", err)
		}
		return json.Marshal(map[string]bool{"revoked": true})
	default:
		return nil, fmt.Errorf("unknown action for delegations: %s", params.Action)
	}
}

func resolveDID(did string) (*types.QueryOutput, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()
	doc, err := am.ResolveDID(ctx, did)
	if err != nil {
		return nil, fmt.Errorf("resolve DID: %w", err)
	}

	vms := make([]types.VerificationMethod, len(doc.VerificationMethods))
	for i, vm := range doc.VerificationMethods {
		vms[i] = types.VerificationMethod{
			ID:         vm.ID,
			Type:       vm.Type,
			Controller: vm.Controller,
			PublicKey:  vm.PublicKey,
			Purpose:    vm.Purpose,
		}
	}

	accounts := make([]types.Account, len(doc.Accounts))
	for i, acc := range doc.Accounts {
		accounts[i] = types.Account{
			Address:      acc.Address,
			ChainID:      acc.ChainID,
			CoinType:     int(acc.CoinType),
			AccountIndex: int(acc.AccountIndex),
			AddressIndex: int(acc.AddressIndex),
			Label:        acc.Label,
			IsDefault:    acc.IsDefault,
		}
	}

	credentials := make([]types.Credential, len(doc.Credentials))
	for i, cred := range doc.Credentials {
		credentials[i] = types.Credential{
			CredentialID:  cred.CredentialID,
			DeviceName:    cred.DeviceName,
			DeviceType:    cred.DeviceType,
			Authenticator: cred.Authenticator,
			Transports:    cred.Transports,
			CreatedAt:     cred.CreatedAt,
			LastUsed:      cred.LastUsed,
		}
	}

	return &types.QueryOutput{
		DID:                 doc.DID,
		Controller:          doc.Controller,
		VerificationMethods: vms,
		Accounts:            accounts,
		Credentials:         credentials,
	}, nil
}

func executeVerificationMethodAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		vms, err := am.ListVerificationMethodsFull(ctx)
		if err != nil {
			return nil, fmt.Errorf("list verification methods: %w", err)
		}
		return json.Marshal(vms)
	case "get":
		if params.Subject == "" {
			return nil, errors.New("subject (method_id) required for get action")
		}
		vm, err := am.GetVerificationMethod(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("get verification method: %w", err)
		}
		return json.Marshal(vm)
	case "delete":
		if params.Subject == "" {
			return nil, errors.New("subject (method_id) required for delete action")
		}
		if err := am.DeleteVerificationMethod(ctx, params.Subject); err != nil {
			return nil, fmt.Errorf("delete verification method: %w", err)
		}
		return json.Marshal(map[string]bool{"deleted": true})
	default:
		return nil, fmt.Errorf("unknown action for verification_methods: %s", params.Action)
	}
}

func executeServiceAction(params *types.FilterParams) (json.RawMessage, error) {
	am, err := keybase.NewActionManager()
	if err != nil {
		return nil, fmt.Errorf("action manager: %w", err)
	}

	ctx := context.Background()

	switch params.Action {
	case "list":
		services, err := am.ListVerifiedServices(ctx)
		if err != nil {
			return nil, fmt.Errorf("list verified services: %w", err)
		}
		return json.Marshal(services)
	case "get":
		if params.Subject == "" {
			return nil, errors.New("subject (origin) required for get action")
		}
		svc, err := am.GetServiceByOrigin(ctx, params.Subject)
		if err != nil {
			return nil, fmt.Errorf("get service: %w", err)
		}
		return json.Marshal(svc)
	case "get_by_id":
		if params.Subject == "" {
			return nil, errors.New("subject (service_id) required for get_by_id action")
		}
		var serviceID int64
		if _, err := fmt.Sscanf(params.Subject, "%d", &serviceID); err != nil {
			return nil, fmt.Errorf("invalid service_id: %w", err)
		}
		svc, err := am.GetServiceByID(ctx, serviceID)
		if err != nil {
			return nil, fmt.Errorf("get service by ID: %w", err)
		}
		return json.Marshal(svc)
	default:
		return nil, fmt.Errorf("unknown action for services: %s", params.Action)
	}
}
