package claude

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

	"github.com/mcuadros/go-defaults"
	"github.com/orbiqd/orbiqd-briefkit/internal/pkg/utils"
	"github.com/orbiqd/orbiqd-briefkit/pkg/briefkit"
)

type ClaudeArguments struct {
	Print           *bool
	Verbose         *bool
	OutputFormat    *string
	Model           *string
	Effort          *string
	ResumeSessionID *string
	DisallowedTools []string
	PermissionMode  *string
	Settings        map[string]any
}

func NewClaudeArguments() *ClaudeArguments {
	return &ClaudeArguments{
		Print:        utils.ToPointer(true),
		Verbose:      utils.ToPointer(true),
		OutputFormat: utils.ToPointer("stream-json"),
		Settings:     make(map[string]any),
	}
}

func (arguments *ClaudeArguments) ToSlice() []string {
	var list []string

	if arguments.Print != nil && *arguments.Print {
		list = append(list, "--print")
	}

	if arguments.Verbose != nil && *arguments.Verbose {
		list = append(list, "--verbose")
	}

	if arguments.OutputFormat != nil {
		list = append(list, "--output-format="+*arguments.OutputFormat)
	}

	if arguments.Model != nil {
		list = append(list, "--model="+*arguments.Model)
	}

	if arguments.Effort != nil {
		list = append(list, "--effort="+*arguments.Effort)
	}

	if arguments.ResumeSessionID != nil {
		list = append(list, "--resume="+*arguments.ResumeSessionID)
	}

	if len(arguments.DisallowedTools) > 0 {
		list = append(list, "--disallowed-tools="+strings.Join(arguments.DisallowedTools, ","))
	}

	if arguments.PermissionMode != nil {
		list = append(list, "--permission-mode="+*arguments.PermissionMode)
	}

	if len(arguments.Settings) > 0 {
		settingsJSON, err := json.Marshal(arguments.Settings)
		if err == nil {
			list = append(list, "--settings="+string(settingsJSON))
		}
	}

	return list
}

func (arguments *ClaudeArguments) ApplyRuntimeConfig(config briefkit.RuntimeConfig) error {
	var claudeConfig RuntimeConfig

	switch typed := config.(type) {
	case nil:
		break
	case RuntimeConfig:
		claudeConfig = typed
	case *RuntimeConfig:
		if typed != nil {
			claudeConfig = *typed
		}
	default:
		payload, err := json.Marshal(config)
		if err != nil {
			return fmt.Errorf("marshal claude runtime config: %w", err)
		}

		if err := json.Unmarshal(payload, &claudeConfig); err != nil {
			return fmt.Errorf("unmarshal claude runtime config: %w", err)
		}
	}

	defaults.SetDefaults(&claudeConfig)

	return nil
}

func (arguments *ClaudeArguments) ApplyRuntimeFeatures(features briefkit.RuntimeFeatures) error {
	if features.EnableSandbox == nil {
		return nil
	}

	if *features.EnableSandbox {
		if arguments.Settings == nil {
			arguments.Settings = make(map[string]any)
		}
		arguments.Settings["sandbox"] = map[string]any{"enabled": true}
	} else {
		arguments.PermissionMode = utils.ToPointer("bypassPermissions")
	}

	return nil
}

func (arguments *ClaudeArguments) ApplyExecutionInput(executionInput briefkit.ExecutionInput) error {
	if executionInput.Model != nil {
		modelValue := strings.TrimSpace(*executionInput.Model)
		if modelValue == "" {
			return errors.New("model cannot be empty")
		}
		arguments.Model = &modelValue
	}

	if executionInput.ReasoningEffort != nil {
		effortValue := strings.TrimSpace(*executionInput.ReasoningEffort)
		if effortValue == "" {
			return errors.New("reasoningEffort cannot be empty")
		}
		arguments.Effort = &effortValue
	}

	if executionInput.ConversationID != nil {
		sessionID := string(*executionInput.ConversationID)
		arguments.ResumeSessionID = &sessionID
	}

	return nil
}
