package server

import (
	"fmt"
	"time"

	"github.com/0x524a/onvif-go"
)

// Config represents the ONVIF server configuration
type Config struct {
	// Server settings
	Host     string        // Bind address (e.g., "0.0.0.0")
	Port     int           // Server port (default: 8080)
	BasePath string        // Base path for services (default: "/onvif")
	Timeout  time.Duration // Request timeout

	// Device information
	DeviceInfo DeviceInfo

	// Authentication
	Username string
	Password string

	// Camera profiles (supports multi-lens cameras)
	Profiles []ProfileConfig

	// Capabilities
	SupportPTZ     bool
	SupportImaging bool
	SupportEvents  bool
}

// DeviceInfo contains device identification information
type DeviceInfo struct {
	Manufacturer    string
	Model           string
	FirmwareVersion string
	SerialNumber    string
	HardwareID      string
}

// ProfileConfig represents a camera profile configuration
type ProfileConfig struct {
	Token        string              // Profile token (unique identifier)
	Name         string              // Profile name
	VideoSource  VideoSourceConfig   // Video source configuration
	AudioSource  *AudioSourceConfig  // Audio source configuration (optional)
	VideoEncoder VideoEncoderConfig  // Video encoder configuration
	AudioEncoder *AudioEncoderConfig // Audio encoder configuration (optional)
	PTZ          *PTZConfig          // PTZ configuration (optional)
	Snapshot     SnapshotConfig      // Snapshot configuration
}

// VideoSourceConfig represents video source configuration
type VideoSourceConfig struct {
	Token      string // Video source token
	Name       string // Video source name
	Resolution Resolution
	Framerate  int
	Bounds     Bounds
}

// AudioSourceConfig represents audio source configuration
type AudioSourceConfig struct {
	Token      string // Audio source token
	Name       string // Audio source name
	SampleRate int    // Sample rate in Hz (e.g., 8000, 16000, 48000)
	Bitrate    int    // Bitrate in kbps
}

// VideoEncoderConfig represents video encoder configuration
type VideoEncoderConfig struct {
	Encoding   string     // JPEG, H264, H265, MPEG4
	Resolution Resolution // Video resolution
	Quality    float64    // Quality (0-100)
	Framerate  int        // Frames per second
	Bitrate    int        // Bitrate in kbps
	GovLength  int        // GOP length
}

// AudioEncoderConfig represents audio encoder configuration
type AudioEncoderConfig struct {
	Encoding   string // G711, G726, AAC
	Bitrate    int    // Bitrate in kbps
	SampleRate int    // Sample rate in Hz
}

// PTZConfig represents PTZ configuration
type PTZConfig struct {
	NodeToken         string    // PTZ node token
	PanRange          Range     // Pan range in degrees
	TiltRange         Range     // Tilt range in degrees
	ZoomRange         Range     // Zoom range
	DefaultSpeed      PTZSpeed  // Default speed
	SupportsContinuous bool     // Supports continuous move
	SupportsAbsolute   bool     // Supports absolute move
	SupportsRelative   bool     // Supports relative move
	Presets           []Preset  // Predefined presets
}

// SnapshotConfig represents snapshot configuration
type SnapshotConfig struct {
	Enabled    bool       // Whether snapshots are supported
	Resolution Resolution // Snapshot resolution
	Quality    float64    // JPEG quality (0-100)
}

// Resolution represents video resolution
type Resolution struct {
	Width  int
	Height int
}

// Bounds represents video bounds
type Bounds struct {
	X      int
	Y      int
	Width  int
	Height int
}

// Range represents a numeric range
type Range struct {
	Min float64
	Max float64
}

// PTZSpeed represents PTZ movement speed
type PTZSpeed struct {
	Pan  float64 // Pan speed (-1.0 to 1.0)
	Tilt float64 // Tilt speed (-1.0 to 1.0)
	Zoom float64 // Zoom speed (-1.0 to 1.0)
}

// Preset represents a PTZ preset position
type Preset struct {
	Token    string      // Preset token
	Name     string      // Preset name
	Position PTZPosition // Position
}

// PTZPosition represents PTZ position
type PTZPosition struct {
	Pan  float64 // Pan position
	Tilt float64 // Tilt position
	Zoom float64 // Zoom position
}

// StreamConfig represents an RTSP stream configuration
type StreamConfig struct {
	ProfileToken string // Associated profile token
	RTSPPath     string // RTSP path (e.g., "/stream1")
	StreamURI    string // Full RTSP URI
}

// Server represents the ONVIF server
type Server struct {
	config       *Config
	streams      map[string]*StreamConfig // Profile token -> stream config
	ptzState     map[string]*PTZState     // Profile token -> PTZ state
	imagingState map[string]*ImagingState // Video source token -> imaging state
	systemTime   time.Time
}

// PTZState represents the current PTZ state
type PTZState struct {
	Position   PTZPosition
	Moving     bool
	PanMoving  bool
	TiltMoving bool
	ZoomMoving bool
	LastUpdate time.Time
}

// ImagingState represents the current imaging settings state
type ImagingState struct {
	Brightness       float64
	Contrast         float64
	Saturation       float64
	Sharpness        float64
	BacklightComp    BacklightCompensation
	Exposure         ExposureSettings
	Focus            FocusSettings
	WhiteBalance     WhiteBalanceSettings
	WideDynamicRange WDRSettings
	IrCutFilter      string // ON, OFF, AUTO
}

// BacklightCompensation represents backlight compensation settings
type BacklightCompensation struct {
	Mode  string  // OFF, ON
	Level float64 // 0-100
}

// ExposureSettings represents exposure settings
type ExposureSettings struct {
	Mode         string  // AUTO, MANUAL
	Priority     string  // LowNoise, FrameRate
	MinExposure  float64
	MaxExposure  float64
	MinGain      float64
	MaxGain      float64
	ExposureTime float64
	Gain         float64
}

// FocusSettings represents focus settings
type FocusSettings struct {
	AutoFocusMode string  // AUTO, MANUAL
	DefaultSpeed  float64
	NearLimit     float64
	FarLimit      float64
	CurrentPos    float64
}

// WhiteBalanceSettings represents white balance settings
type WhiteBalanceSettings struct {
	Mode   string  // AUTO, MANUAL
	CrGain float64
	CbGain float64
}

// WDRSettings represents wide dynamic range settings
type WDRSettings struct {
	Mode  string  // OFF, ON
	Level float64 // 0-100
}

// DefaultConfig returns a default server configuration with a multi-lens camera setup
func DefaultConfig() *Config {
	return &Config{
		Host:     "0.0.0.0",
		Port:     8080,
		BasePath: "/onvif",
		Timeout:  30 * time.Second,
		DeviceInfo: DeviceInfo{
			Manufacturer:    "onvif-go",
			Model:           "Virtual Multi-Lens Camera",
			FirmwareVersion: "1.0.0",
			SerialNumber:    "SN-12345678",
			HardwareID:      "HW-87654321",
		},
		Username:       "admin",
		Password:       "admin",
		SupportPTZ:     true,
		SupportImaging: true,
		SupportEvents:  false,
		Profiles: []ProfileConfig{
			{
				Token: "profile_0",
				Name:  "Main Camera - High Quality",
				VideoSource: VideoSourceConfig{
					Token:      "video_source_0",
					Name:       "Main Camera",
					Resolution: Resolution{Width: 1920, Height: 1080},
					Framerate:  30,
					Bounds:     Bounds{X: 0, Y: 0, Width: 1920, Height: 1080},
				},
				VideoEncoder: VideoEncoderConfig{
					Encoding:   "H264",
					Resolution: Resolution{Width: 1920, Height: 1080},
					Quality:    80,
					Framerate:  30,
					Bitrate:    4096,
					GovLength:  30,
				},
				PTZ: &PTZConfig{
					NodeToken:          "ptz_node_0",
					PanRange:           Range{Min: -180, Max: 180},
					TiltRange:          Range{Min: -90, Max: 90},
					ZoomRange:          Range{Min: 0, Max: 1},
					DefaultSpeed:       PTZSpeed{Pan: 0.5, Tilt: 0.5, Zoom: 0.5},
					SupportsContinuous: true,
					SupportsAbsolute:   true,
					SupportsRelative:   true,
					Presets: []Preset{
						{Token: "preset_0", Name: "Home", Position: PTZPosition{Pan: 0, Tilt: 0, Zoom: 0}},
						{Token: "preset_1", Name: "Entrance", Position: PTZPosition{Pan: -45, Tilt: -10, Zoom: 0.5}},
					},
				},
				Snapshot: SnapshotConfig{
					Enabled:    true,
					Resolution: Resolution{Width: 1920, Height: 1080},
					Quality:    85,
				},
			},
			{
				Token: "profile_1",
				Name:  "Wide Angle Camera",
				VideoSource: VideoSourceConfig{
					Token:      "video_source_1",
					Name:       "Wide Angle Camera",
					Resolution: Resolution{Width: 1280, Height: 720},
					Framerate:  30,
					Bounds:     Bounds{X: 0, Y: 0, Width: 1280, Height: 720},
				},
				VideoEncoder: VideoEncoderConfig{
					Encoding:   "H264",
					Resolution: Resolution{Width: 1280, Height: 720},
					Quality:    75,
					Framerate:  30,
					Bitrate:    2048,
					GovLength:  30,
				},
				Snapshot: SnapshotConfig{
					Enabled:    true,
					Resolution: Resolution{Width: 1280, Height: 720},
					Quality:    80,
				},
			},
			{
				Token: "profile_2",
				Name:  "Telephoto Camera",
				VideoSource: VideoSourceConfig{
					Token:      "video_source_2",
					Name:       "Telephoto Camera",
					Resolution: Resolution{Width: 1920, Height: 1080},
					Framerate:  25,
					Bounds:     Bounds{X: 0, Y: 0, Width: 1920, Height: 1080},
				},
				VideoEncoder: VideoEncoderConfig{
					Encoding:   "H264",
					Resolution: Resolution{Width: 1920, Height: 1080},
					Quality:    85,
					Framerate:  25,
					Bitrate:    6144,
					GovLength:  25,
				},
				PTZ: &PTZConfig{
					NodeToken:          "ptz_node_2",
					PanRange:           Range{Min: -180, Max: 180},
					TiltRange:          Range{Min: -90, Max: 90},
					ZoomRange:          Range{Min: 0, Max: 3},
					DefaultSpeed:       PTZSpeed{Pan: 0.3, Tilt: 0.3, Zoom: 0.3},
					SupportsContinuous: true,
					SupportsAbsolute:   true,
					SupportsRelative:   true,
					Presets: []Preset{
						{Token: "preset_2_0", Name: "Home", Position: PTZPosition{Pan: 0, Tilt: 0, Zoom: 0}},
						{Token: "preset_2_1", Name: "Zoom In", Position: PTZPosition{Pan: 0, Tilt: 0, Zoom: 2}},
					},
				},
				Snapshot: SnapshotConfig{
					Enabled:    true,
					Resolution: Resolution{Width: 1920, Height: 1080},
					Quality:    90,
				},
			},
		},
	}
}

// ServiceEndpoints returns the service endpoint URLs
func (c *Config) ServiceEndpoints(host string) map[string]string {
	if host == "" {
		host = c.Host
		if host == "0.0.0.0" || host == "" {
			host = "localhost"
		}
	}

	baseURL := ""
	if c.Port == 80 {
		baseURL = "http://" + host + c.BasePath
	} else {
		// Import fmt at the top to use Sprintf
		baseURL = fmt.Sprintf("http://%s:%d%s", host, c.Port, c.BasePath)
	}

	endpoints := map[string]string{
		"device":  baseURL + "/device_service",
		"media":   baseURL + "/media_service",
		"imaging": baseURL + "/imaging_service",
	}

	if c.SupportPTZ {
		endpoints["ptz"] = baseURL + "/ptz_service"
	}

	if c.SupportEvents {
		endpoints["events"] = baseURL + "/events_service"
	}

	return endpoints
}

// ToONVIFProfile converts a ProfileConfig to an ONVIF Profile
func (p *ProfileConfig) ToONVIFProfile() *onvif.Profile {
	profile := &onvif.Profile{
		Token: p.Token,
		Name:  p.Name,
		VideoSourceConfiguration: &onvif.VideoSourceConfiguration{
			Token:       p.VideoSource.Token,
			Name:        p.VideoSource.Name,
			SourceToken: p.VideoSource.Token,
			Bounds: &onvif.IntRectangle{
				X:      p.VideoSource.Bounds.X,
				Y:      p.VideoSource.Bounds.Y,
				Width:  p.VideoSource.Bounds.Width,
				Height: p.VideoSource.Bounds.Height,
			},
		},
		VideoEncoderConfiguration: &onvif.VideoEncoderConfiguration{
			Token:    p.Token + "_encoder",
			Name:     p.Name + " Encoder",
			Encoding: p.VideoEncoder.Encoding,
			Resolution: &onvif.VideoResolution{
				Width:  p.VideoEncoder.Resolution.Width,
				Height: p.VideoEncoder.Resolution.Height,
			},
			Quality: p.VideoEncoder.Quality,
			RateControl: &onvif.VideoRateControl{
				FrameRateLimit: p.VideoEncoder.Framerate,
				BitrateLimit:   p.VideoEncoder.Bitrate,
			},
		},
	}

	if p.PTZ != nil {
		profile.PTZConfiguration = &onvif.PTZConfiguration{
			Token:     p.PTZ.NodeToken,
			Name:      p.Name + " PTZ",
			NodeToken: p.PTZ.NodeToken,
		}
	}

	return profile
}
