// ABOUTME: Core type definitions for EdgeXR Master Controller SDK
// ABOUTME: These types are based on the swagger API specification and existing client patterns

package v2

import (
	"encoding/json"
	"fmt"
	"time"
)

// App field constants for partial updates (based on EdgeXR API specification)
const (
	AppFieldKey                         = "2"
	AppFieldKeyOrganization             = "2.1"
	AppFieldKeyName                     = "2.2"
	AppFieldKeyVersion                  = "2.3"
	AppFieldImagePath                   = "4"
	AppFieldImageType                   = "5"
	AppFieldAccessPorts                 = "7"
	AppFieldDefaultFlavor               = "9"
	AppFieldDefaultFlavorName           = "9.1"
	AppFieldAuthPublicKey               = "12"
	AppFieldCommand                     = "13"
	AppFieldAnnotations                 = "14"
	AppFieldDeployment                  = "15"
	AppFieldDeploymentManifest          = "16"
	AppFieldDeploymentGenerator         = "17"
	AppFieldAndroidPackageName          = "18"
	AppFieldDelOpt                      = "20"
	AppFieldConfigs                     = "21"
	AppFieldConfigsKind                 = "21.1"
	AppFieldConfigsConfig               = "21.2"
	AppFieldScaleWithCluster            = "22"
	AppFieldInternalPorts               = "23"
	AppFieldRevision                    = "24"
	AppFieldOfficialFqdn                = "25"
	AppFieldMd5Sum                      = "26"
	AppFieldAutoProvPolicy              = "28"
	AppFieldAccessType                  = "29"
	AppFieldDeletePrepare               = "31"
	AppFieldAutoProvPolicies            = "32"
	AppFieldTemplateDelimiter           = "33"
	AppFieldSkipHcPorts                 = "34"
	AppFieldCreatedAt                   = "35"
	AppFieldCreatedAtSeconds            = "35.1"
	AppFieldCreatedAtNanos              = "35.2"
	AppFieldUpdatedAt                   = "36"
	AppFieldUpdatedAtSeconds            = "36.1"
	AppFieldUpdatedAtNanos              = "36.2"
	AppFieldTrusted                     = "37"
	AppFieldRequiredOutboundConnections = "38"
	AppFieldAllowServerless             = "39"
	AppFieldServerlessConfig            = "40"
	AppFieldVmAppOsType                 = "41"
	AppFieldAlertPolicies               = "42"
	AppFieldQosSessionProfile           = "43"
	AppFieldQosSessionDuration          = "44"
)

// AppInstance field constants for partial updates (based on EdgeXR API specification)
const (
	AppInstFieldKey                                               = "2"
	AppInstFieldKeyAppKey                                         = "2.1"
	AppInstFieldKeyAppKeyOrganization                             = "2.1.1"
	AppInstFieldKeyAppKeyName                                     = "2.1.2"
	AppInstFieldKeyAppKeyVersion                                  = "2.1.3"
	AppInstFieldKeyClusterInstKey                                 = "2.4"
	AppInstFieldKeyClusterInstKeyClusterKey                       = "2.4.1"
	AppInstFieldKeyClusterInstKeyClusterKeyName                   = "2.4.1.1"
	AppInstFieldKeyClusterInstKeyCloudletKey                      = "2.4.2"
	AppInstFieldKeyClusterInstKeyCloudletKeyOrganization          = "2.4.2.1"
	AppInstFieldKeyClusterInstKeyCloudletKeyName                  = "2.4.2.2"
	AppInstFieldKeyClusterInstKeyCloudletKeyFederatedOrganization = "2.4.2.3"
	AppInstFieldKeyClusterInstKeyOrganization                     = "2.4.3"
	AppInstFieldCloudletLoc                                       = "3"
	AppInstFieldCloudletLocLatitude                               = "3.1"
	AppInstFieldCloudletLocLongitude                              = "3.2"
	AppInstFieldCloudletLocHorizontalAccuracy                     = "3.3"
	AppInstFieldCloudletLocVerticalAccuracy                       = "3.4"
	AppInstFieldCloudletLocAltitude                               = "3.5"
	AppInstFieldCloudletLocCourse                                 = "3.6"
	AppInstFieldCloudletLocSpeed                                  = "3.7"
	AppInstFieldCloudletLocTimestamp                              = "3.8"
	AppInstFieldCloudletLocTimestampSeconds                       = "3.8.1"
	AppInstFieldCloudletLocTimestampNanos                         = "3.8.2"
	AppInstFieldUri                                               = "4"
	AppInstFieldLiveness                                          = "6"
	AppInstFieldMappedPorts                                       = "9"
	AppInstFieldMappedPortsProto                                  = "9.1"
	AppInstFieldMappedPortsInternalPort                           = "9.2"
	AppInstFieldMappedPortsPublicPort                             = "9.3"
	AppInstFieldMappedPortsFqdnPrefix                             = "9.5"
	AppInstFieldMappedPortsEndPort                                = "9.6"
	AppInstFieldMappedPortsTls                                    = "9.7"
	AppInstFieldMappedPortsNginx                                  = "9.8"
	AppInstFieldMappedPortsMaxPktSize                             = "9.9"
	AppInstFieldFlavor                                            = "12"
	AppInstFieldFlavorName                                        = "12.1"
	AppInstFieldState                                             = "14"
	AppInstFieldErrors                                            = "15"
	AppInstFieldCrmOverride                                       = "16"
	AppInstFieldRuntimeInfo                                       = "17"
	AppInstFieldRuntimeInfoContainerIds                           = "17.1"
	AppInstFieldCreatedAt                                         = "21"
	AppInstFieldCreatedAtSeconds                                  = "21.1"
	AppInstFieldCreatedAtNanos                                    = "21.2"
	AppInstFieldAutoClusterIpAccess                               = "22"
	AppInstFieldRevision                                          = "24"
	AppInstFieldForceUpdate                                       = "25"
	AppInstFieldUpdateMultiple                                    = "26"
	AppInstFieldConfigs                                           = "27"
	AppInstFieldConfigsKind                                       = "27.1"
	AppInstFieldConfigsConfig                                     = "27.2"
	AppInstFieldHealthCheck                                       = "29"
	AppInstFieldExternalVolumeSize                                = "32"
	AppInstFieldAvailabilityZone                                  = "33"
	AppInstFieldVmFlavor                                          = "34"
	AppInstFieldOptRes                                            = "35"
	AppInstFieldUpdatedAt                                         = "36"
	AppInstFieldUpdatedAtSeconds                                  = "36.1"
	AppInstFieldUpdatedAtNanos                                    = "36.2"
	AppInstFieldRealClusterName                                   = "37"
	AppInstFieldInternalPortToLbIp                                = "38"
	AppInstFieldInternalPortToLbIpKey                             = "38.1"
	AppInstFieldInternalPortToLbIpValue                           = "38.2"
	AppInstFieldDedicatedIp                                       = "39"
	AppInstFieldUniqueId                                          = "40"
	AppInstFieldDnsLabel                                          = "41"
)

// Message interface for types that can provide error messages
type Message interface {
	GetMessage() string
}

// Base message type for API responses
type msg struct {
	Message string `json:"message,omitempty"`
}

func (m msg) GetMessage() string {
	return m.Message
}

// AppKey uniquely identifies an application
type AppKey struct {
	Organization string `json:"organization"`
	Name         string `json:"name,omitempty"`
	Version      string `json:"version,omitempty"`
}

// CloudletKey uniquely identifies a cloudlet
type CloudletKey struct {
	Organization string `json:"organization"`
	Name         string `json:"name"`
}

// AppInstanceKey uniquely identifies an application instance
type AppInstanceKey struct {
	Organization string      `json:"organization"`
	Name         string      `json:"name"`
	CloudletKey  CloudletKey `json:"cloudlet_key"`
}

// Flavor defines resource allocation for instances
type Flavor struct {
	Name string `json:"name"`
}

// ServerlessConfig defines serverless deployment configuration
type ServerlessConfig struct {
	MinReplicas int `json:"min_replicas,omitempty"` // number of replicas (at least 1)
	RAM         int `json:"ram,omitempty"`          // RAM in MB
	VCPUs       int `json:"vcpus,omitempty"`        // Virtual CPUs
}

// SecurityRule defines network access rules
type SecurityRule struct {
	PortRangeMax int    `json:"port_range_max"`
	PortRangeMin int    `json:"port_range_min"`
	Protocol     string `json:"protocol"`
	RemoteCIDR   string `json:"remote_cidr"`
}

// App represents an application definition
type App struct {
	msg                         `json:",inline"`
	Key                         AppKey           `json:"key"`
	Deployment                  string           `json:"deployment,omitempty"`
	ImageType                   string           `json:"image_type,omitempty"`
	ImagePath                   string           `json:"image_path,omitempty"`
	AccessPorts                 string           `json:"access_ports,omitempty"`
	AllowServerless             bool             `json:"allow_serverless,omitempty"`
	DefaultFlavor               Flavor           `json:"defaultFlavor,omitempty"`
	ServerlessConfig            ServerlessConfig `json:"serverless_config,omitempty"`
	DeploymentGenerator         string           `json:"deployment_generator,omitempty"`
	DeploymentManifest          string           `json:"deployment_manifest,omitempty"`
	RequiredOutboundConnections []SecurityRule   `json:"required_outbound_connections"`
	GlobalID                    string           `json:"global_id,omitempty"`
	CreatedAt                   string           `json:"created_at,omitempty"`
	UpdatedAt                   string           `json:"updated_at,omitempty"`
}

// AppInstance represents a deployed application instance
type AppInstance struct {
	msg         `json:",inline"`
	Key         AppInstanceKey `json:"key"`
	AppKey      AppKey         `json:"app_key,omitempty"`
	CloudletLoc CloudletLoc    `json:"cloudlet_loc,omitempty"`
	Flavor      Flavor         `json:"flavor,omitempty"`
	State       string         `json:"state,omitempty"`
	IngressURL  string         `json:"ingress_url,omitempty"`
	UniqueID    string         `json:"unique_id,omitempty"`
	CreatedAt   string         `json:"created_at,omitempty"`
	UpdatedAt   string         `json:"updated_at,omitempty"`
}

// Cloudlet represents edge infrastructure
type Cloudlet struct {
	msg           `json:",inline"`
	Key           CloudletKey `json:"key"`
	Location      Location    `json:"location"`
	IpSupport     string      `json:"ip_support,omitempty"`
	NumDynamicIps int32       `json:"num_dynamic_ips,omitempty"`
	State         string      `json:"state,omitempty"`
	Flavor        Flavor      `json:"flavor,omitempty"`
	PhysicalName  string      `json:"physical_name,omitempty"`
	Region        string      `json:"region,omitempty"`
	NotifySrvAddr string      `json:"notify_srv_addr,omitempty"`
}

// Location represents geographical coordinates
type Location struct {
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

// CloudletLoc represents geographical coordinates for cloudlets
type CloudletLoc struct {
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

// Input types for API operations

// NewAppInput represents input for creating an application
type NewAppInput struct {
	Region string `json:"region"`
	App    App    `json:"app"`
}

// NewAppInstanceInput represents input for creating an app instance
type NewAppInstanceInput struct {
	Region  string      `json:"region"`
	AppInst AppInstance `json:"appinst"`
}

// NewCloudletInput represents input for creating a cloudlet
type NewCloudletInput struct {
	Region   string   `json:"region"`
	Cloudlet Cloudlet `json:"cloudlet"`
}

// UpdateAppInput represents input for updating an application
type UpdateAppInput struct {
	Region string `json:"region"`
	App    App    `json:"app"`
}

// UpdateAppInstanceInput represents input for updating an app instance
type UpdateAppInstanceInput struct {
	Region  string      `json:"region"`
	AppInst AppInstance `json:"appinst"`
}

// DeleteAppInput represents input for deleting an application
type DeleteAppInput struct {
	Region string `json:"region"`
	App    struct {
		Key AppKey `json:"key"`
	} `json:"app"`
}

// DeleteAppInstanceInput represents input for deleting an app instance
type DeleteAppInstanceInput struct {
	Region  string `json:"region"`
	AppInst struct {
		Key AppInstanceKey `json:"key"`
	} `json:"appinst"`
}

// Response wrapper types

// Response wraps a single API response
type Response[T Message] struct {
	ResultResponse `json:",inline"`
	Data           T `json:"data"`
}

func (res *Response[T]) HasData() bool {
	return !res.IsMessage()
}

func (res *Response[T]) IsMessage() bool {
	return res.Data.GetMessage() != ""
}

// ResultResponse represents an API result with error code
type ResultResponse struct {
	Result struct {
		Message string `json:"message"`
		Code    int    `json:"code"`
	} `json:"result"`
}

func (r *ResultResponse) IsError() bool {
	return r.Result.Code >= 400
}

func (r *ResultResponse) GetMessage() string {
	return r.Result.Message
}

func (r *ResultResponse) GetCode() int {
	return r.Result.Code
}

// Responses wraps multiple API responses with metadata
type Responses[T Message] struct {
	Responses  []Response[T] `json:"responses,omitempty"`
	StatusCode int           `json:"-"`
	Errors     []error       `json:"-"`
}

func (r *Responses[T]) GetData() []T {
	var data []T
	for _, v := range r.Responses {
		if v.HasData() {
			data = append(data, v.Data)
		}
	}
	return data
}

func (r *Responses[T]) GetMessages() []string {
	var messages []string
	for _, v := range r.Responses {
		if v.IsMessage() {
			messages = append(messages, v.Data.GetMessage())
		}
		if v.Result.Message != "" {
			messages = append(messages, v.Result.Message)
		}
	}
	return messages
}

func (r *Responses[T]) IsSuccessful() bool {
	return len(r.Errors) == 0 && (r.StatusCode >= 200 && r.StatusCode < 400)
}

func (r *Responses[T]) Error() error {
	if r.IsSuccessful() {
		return nil
	}
	return &APIError{
		StatusCode: r.StatusCode,
		Messages:   r.GetMessages(),
	}
}

// APIError represents an API error with details
type APIError struct {
	StatusCode int      `json:"status_code"`
	Code       string   `json:"code,omitempty"`
	Messages   []string `json:"messages,omitempty"`
	Body       []byte   `json:"-"`
}

func (e *APIError) Error() string {
	jsonErr, err := json.Marshal(e)
	if err != nil {
		return fmt.Sprintf("API error: %v", err)
	}
	return fmt.Sprintf("API error: %s", jsonErr)
}

// Filter types for querying

// AppFilter represents filters for app queries
type AppFilter struct {
	App    App    `json:"app"`
	Region string `json:"region"`
}

// AppInstanceFilter represents filters for app instance queries
type AppInstanceFilter struct {
	AppInstance AppInstance `json:"appinst"`
	Region      string      `json:"region"`
}

// CloudletFilter represents filters for cloudlet queries
type CloudletFilter struct {
	Cloudlet Cloudlet `json:"cloudlet"`
	Region   string   `json:"region"`
}

// CloudletManifest represents cloudlet deployment manifest
type CloudletManifest struct {
	Manifest     string    `json:"manifest"`
	LastModified time.Time `json:"last_modified,omitempty"`
}

// CloudletResourceUsage represents cloudlet resource utilization
type CloudletResourceUsage struct {
	CloudletKey CloudletKey            `json:"cloudlet_key"`
	Region      string                 `json:"region"`
	Usage       map[string]interface{} `json:"usage"`
}

type ErrorMessage struct {
	Message string
}
