package faasclient

import (
	"encoding/json"
	"time"

	"github.com/google/uuid"
)

// RuntimeType represents supported function runtimes
type RuntimeType string

const (
	RuntimeNodeJS18 RuntimeType = "nodejs18"
	RuntimePython39 RuntimeType = "python3.9"
	RuntimeGo120    RuntimeType = "go1.20"
	RuntimeCustom   RuntimeType = "custom"
)

// ExecutionStatus represents the status of function execution
type ExecutionStatus string

const (
	StatusPending   ExecutionStatus = "pending"
	StatusRunning   ExecutionStatus = "running"
	StatusCompleted ExecutionStatus = "completed"
	StatusFailed    ExecutionStatus = "failed"
	StatusTimeout   ExecutionStatus = "timeout"
	StatusCanceled  ExecutionStatus = "canceled"
)

// OwnerType represents the type of owner
type OwnerType string

const (
	OwnerTypeIndividual OwnerType = "individual"
	OwnerTypeTeam       OwnerType = "team"
)

// Owner represents ownership information
type Owner struct {
	Type  OwnerType `json:"type"`
	Name  string    `json:"name"`
	Owner string    `json:"owner"`
}

// Duration wraps time.Duration for JSON marshaling
type Duration time.Duration

func (d Duration) MarshalJSON() ([]byte, error) {
	return json.Marshal(time.Duration(d).String())
}

func (d *Duration) UnmarshalJSON(b []byte) error {
	var v interface{}
	if err := json.Unmarshal(b, &v); err != nil {
		return err
	}
	switch value := v.(type) {
	case float64:
		*d = Duration(time.Duration(value))
		return nil
	case string:
		tmp, err := time.ParseDuration(value)
		if err != nil {
			return err
		}
		*d = Duration(tmp)
		return nil
	default:
		return nil
	}
}

// FunctionDefinition represents a serverless function
type FunctionDefinition struct {
	ID          uuid.UUID         `json:"id"`
	Name        string            `json:"name"`
	AppID       string            `json:"app_id"`
	Runtime     RuntimeType       `json:"runtime"`
	Image       string            `json:"image"`
	Handler     string            `json:"handler"`
	Code        string            `json:"code,omitempty"`
	Environment map[string]string `json:"environment,omitempty"`
	Timeout     Duration          `json:"timeout"`
	Memory      int               `json:"memory"`
	Owner       Owner             `json:"owner"`
	CreatedAt   time.Time         `json:"created_at"`
	UpdatedAt   time.Time         `json:"updated_at"`
}

// FunctionExecution represents a function execution
type FunctionExecution struct {
	ID          uuid.UUID       `json:"id"`
	FunctionID  uuid.UUID       `json:"function_id"`
	Status      ExecutionStatus `json:"status"`
	Input       json.RawMessage `json:"input,omitempty"`
	Output      json.RawMessage `json:"output,omitempty"`
	Error       string          `json:"error,omitempty"`
	Duration    time.Duration   `json:"duration"`
	MemoryUsed  int             `json:"memory_used"`
	Logs        []string        `json:"logs,omitempty"`
	ContainerID string          `json:"container_id,omitempty"`
	ExecutorID  string          `json:"executor_id"`
	CreatedAt   time.Time       `json:"created_at"`
	StartedAt   *time.Time      `json:"started_at,omitempty"`
	CompletedAt *time.Time      `json:"completed_at,omitempty"`
}

// CreateFunctionRequest represents a request to create a new function
type CreateFunctionRequest struct {
	Name        string            `json:"name"`
	AppID       string            `json:"app_id"`
	Runtime     RuntimeType       `json:"runtime"`
	Image       string            `json:"image"`
	Handler     string            `json:"handler"`
	Code        string            `json:"code,omitempty"`
	Environment map[string]string `json:"environment,omitempty"`
	Timeout     Duration          `json:"timeout"`
	Memory      int               `json:"memory"`
	Owner       Owner             `json:"owner"`
}

// UpdateFunctionRequest represents a request to update an existing function
type UpdateFunctionRequest struct {
	Name        *string           `json:"name,omitempty"`
	Runtime     *RuntimeType      `json:"runtime,omitempty"`
	Image       *string           `json:"image,omitempty"`
	Handler     *string           `json:"handler,omitempty"`
	Code        *string           `json:"code,omitempty"`
	Environment map[string]string `json:"environment,omitempty"`
	Timeout     *Duration         `json:"timeout,omitempty"`
	Memory      *int              `json:"memory,omitempty"`
	Owner       *Owner            `json:"owner,omitempty"`
}

// ExecuteFunctionRequest represents a request to execute a function
type ExecuteFunctionRequest struct {
	FunctionID uuid.UUID       `json:"function_id"`
	Input      json.RawMessage `json:"input,omitempty"`
	Async      bool            `json:"async,omitempty"`
}

// ExecuteFunctionResponse represents a response for function execution
type ExecuteFunctionResponse struct {
	ExecutionID uuid.UUID       `json:"execution_id"`
	Status      ExecutionStatus `json:"status"`
	Output      json.RawMessage `json:"output,omitempty"`
	Error       string          `json:"error,omitempty"`
	Duration    time.Duration   `json:"duration,omitempty"`
	MemoryUsed  int             `json:"memory_used,omitempty"`
}

// DeployFunctionRequest represents a request to deploy a function
type DeployFunctionRequest struct {
	FunctionID uuid.UUID `json:"function_id"`
	Force      bool      `json:"force,omitempty"`
}

// DeployFunctionResponse represents a response for function deployment
type DeployFunctionResponse struct {
	Status  string `json:"status"`
	Message string `json:"message,omitempty"`
	Image   string `json:"image,omitempty"`
	ImageID string `json:"image_id,omitempty"`
}

// ListFunctionsResponse represents the response for listing functions
type ListFunctionsResponse struct {
	Functions []FunctionDefinition `json:"functions"`
	Limit     int                  `json:"limit"`
	Offset    int                  `json:"offset"`
}

// ListExecutionsResponse represents the response for listing executions
type ListExecutionsResponse struct {
	Executions []FunctionExecution `json:"executions"`
	Limit      int                 `json:"limit"`
	Offset     int                 `json:"offset"`
}

// GetLogsResponse represents the response for getting execution logs
type GetLogsResponse struct {
	Logs []string `json:"logs"`
}

// GetRunningExecutionsResponse represents the response for getting running executions
type GetRunningExecutionsResponse struct {
	Executions []FunctionExecution `json:"executions"`
	Count      int                 `json:"count"`
}