package server

import (
	"encoding/xml"
	"fmt"
	"time"

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

const (
	defaultHost     = "0.0.0.0"
	defaultHostname = "localhost"
)

// Device service SOAP message types

// GetDeviceInformationResponse represents GetDeviceInformation response.
type GetDeviceInformationResponse struct {
	XMLName         xml.Name `xml:"http://www.onvif.org/ver10/device/wsdl GetDeviceInformationResponse"`
	Manufacturer    string   `xml:"Manufacturer"`
	Model           string   `xml:"Model"`
	FirmwareVersion string   `xml:"FirmwareVersion"`
	SerialNumber    string   `xml:"SerialNumber"`
	HardwareID      string   `xml:"HardwareId"`
}

// GetCapabilitiesResponse represents GetCapabilities response.
type GetCapabilitiesResponse struct {
	XMLName      xml.Name      `xml:"http://www.onvif.org/ver10/device/wsdl GetCapabilitiesResponse"`
	Capabilities *Capabilities `xml:"Capabilities"`
}

// Capabilities represents device capabilities.
type Capabilities struct {
	Analytics *AnalyticsCapabilities `xml:"Analytics,omitempty"`
	Device    *DeviceCapabilities    `xml:"Device"`
	Events    *EventCapabilities     `xml:"Events,omitempty"`
	Imaging   *ImagingCapabilities   `xml:"Imaging,omitempty"`
	Media     *MediaCapabilities     `xml:"Media"`
	PTZ       *PTZCapabilities       `xml:"PTZ,omitempty"`
}

// AnalyticsCapabilities represents analytics service capabilities.
type AnalyticsCapabilities struct {
	XAddr                  string `xml:"XAddr"`
	RuleSupport            bool   `xml:"RuleSupport,attr"`
	AnalyticsModuleSupport bool   `xml:"AnalyticsModuleSupport,attr"`
}

// DeviceCapabilities represents device service capabilities.
type DeviceCapabilities struct {
	XAddr    string                `xml:"XAddr"`
	Network  *NetworkCapabilities  `xml:"Network,omitempty"`
	System   *SystemCapabilities   `xml:"System,omitempty"`
	IO       *IOCapabilities       `xml:"IO,omitempty"`
	Security *SecurityCapabilities `xml:"Security,omitempty"`
}

// NetworkCapabilities represents network capabilities.
type NetworkCapabilities struct {
	IPFilter          bool `xml:"IPFilter,attr"`
	ZeroConfiguration bool `xml:"ZeroConfiguration,attr"`
	IPVersion6        bool `xml:"IPVersion6,attr"`
	DynDNS            bool `xml:"DynDNS,attr"`
}

// SystemCapabilities represents system capabilities.
type SystemCapabilities struct {
	DiscoveryResolve bool `xml:"DiscoveryResolve,attr"`
	DiscoveryBye     bool `xml:"DiscoveryBye,attr"`
	RemoteDiscovery  bool `xml:"RemoteDiscovery,attr"`
	SystemBackup     bool `xml:"SystemBackup,attr"`
	SystemLogging    bool `xml:"SystemLogging,attr"`
	FirmwareUpgrade  bool `xml:"FirmwareUpgrade,attr"`
}

// IOCapabilities represents I/O capabilities.
type IOCapabilities struct {
	InputConnectors int `xml:"InputConnectors,attr"`
	RelayOutputs    int `xml:"RelayOutputs,attr"`
}

// SecurityCapabilities represents security capabilities.
type SecurityCapabilities struct {
	TLS11                bool `xml:"TLS1.1,attr"`
	TLS12                bool `xml:"TLS1.2,attr"`
	OnboardKeyGeneration bool `xml:"OnboardKeyGeneration,attr"`
	AccessPolicyConfig   bool `xml:"AccessPolicyConfig,attr"`
	X509Token            bool `xml:"X.509Token,attr"`
	SAMLToken            bool `xml:"SAMLToken,attr"`
	KerberosToken        bool `xml:"KerberosToken,attr"`
	RELToken             bool `xml:"RELToken,attr"`
}

// EventCapabilities represents event service capabilities.
type EventCapabilities struct {
	XAddr                         string `xml:"XAddr"`
	WSSubscriptionPolicySupport   bool   `xml:"WSSubscriptionPolicySupport,attr"`
	WSPullPointSupport            bool   `xml:"WSPullPointSupport,attr"`
	WSPausableSubscriptionSupport bool   `xml:"WSPausableSubscriptionManagerInterfaceSupport,attr"`
}

// ImagingCapabilities represents imaging service capabilities.
type ImagingCapabilities struct {
	XAddr string `xml:"XAddr"`
}

// MediaCapabilities represents media service capabilities.
type MediaCapabilities struct {
	XAddr                 string                 `xml:"XAddr"`
	StreamingCapabilities *StreamingCapabilities `xml:"StreamingCapabilities"`
}

// StreamingCapabilities represents streaming capabilities.
type StreamingCapabilities struct {
	RTPMulticast bool `xml:"RTPMulticast,attr"`
	RTPTCP       bool `xml:"RTP_TCP,attr"`
	RTPRTSPTCP   bool `xml:"RTP_RTSP_TCP,attr"`
}

// PTZCapabilities represents PTZ service capabilities.
type PTZCapabilities struct {
	XAddr string `xml:"XAddr"`
}

// GetServicesResponse represents GetServices response.
type GetServicesResponse struct {
	XMLName xml.Name  `xml:"http://www.onvif.org/ver10/device/wsdl GetServicesResponse"`
	Service []Service `xml:"Service"`
}

// Service represents a service.
type Service struct {
	Namespace string  `xml:"Namespace"`
	XAddr     string  `xml:"XAddr"`
	Version   Version `xml:"Version"`
}

// Version represents service version.
type Version struct {
	Major int `xml:"Major"`
	Minor int `xml:"Minor"`
}

// SystemRebootResponse represents SystemReboot response.
type SystemRebootResponse struct {
	XMLName xml.Name `xml:"http://www.onvif.org/ver10/device/wsdl SystemRebootResponse"`
	Message string   `xml:"Message"`
}

// Device service handlers

// HandleGetDeviceInformation handles GetDeviceInformation request.
func (s *Server) HandleGetDeviceInformation(body interface{}) (interface{}, error) {
	return &GetDeviceInformationResponse{
		Manufacturer:    s.config.DeviceInfo.Manufacturer,
		Model:           s.config.DeviceInfo.Model,
		FirmwareVersion: s.config.DeviceInfo.FirmwareVersion,
		SerialNumber:    s.config.DeviceInfo.SerialNumber,
		HardwareID:      s.config.DeviceInfo.HardwareID,
	}, nil
}

// HandleGetCapabilities handles GetCapabilities request.
func (s *Server) HandleGetCapabilities(body interface{}) (interface{}, error) {
	// Get the host from the request (in a real implementation)
	// For now, use a placeholder
	host := s.config.Host
	if host == defaultHost || host == "" {
		host = defaultHostname
	}

	baseURL := fmt.Sprintf("http://%s:%d%s", host, s.config.Port, s.config.BasePath)

	capabilities := &Capabilities{
		Device: &DeviceCapabilities{
			XAddr: baseURL + "/device_service",
			Network: &NetworkCapabilities{
				IPFilter:          false,
				ZeroConfiguration: false,
				IPVersion6:        false,
				DynDNS:            false,
			},
			System: &SystemCapabilities{
				DiscoveryResolve: true,
				DiscoveryBye:     true,
				RemoteDiscovery:  true,
				SystemBackup:     false,
				SystemLogging:    false,
				FirmwareUpgrade:  false,
			},
			IO: &IOCapabilities{
				InputConnectors: 0,
				RelayOutputs:    0,
			},
			Security: &SecurityCapabilities{
				TLS11:                false,
				TLS12:                false,
				OnboardKeyGeneration: false,
				AccessPolicyConfig:   false,
				X509Token:            false,
				SAMLToken:            false,
				KerberosToken:        false,
				RELToken:             false,
			},
		},
		Media: &MediaCapabilities{
			XAddr: baseURL + "/media_service",
			StreamingCapabilities: &StreamingCapabilities{
				RTPMulticast: false,
				RTPTCP:       true,
				RTPRTSPTCP:   true,
			},
		},
	}

	if s.config.SupportPTZ {
		capabilities.PTZ = &PTZCapabilities{
			XAddr: baseURL + "/ptz_service",
		}
	}

	if s.config.SupportImaging {
		capabilities.Imaging = &ImagingCapabilities{
			XAddr: baseURL + "/imaging_service",
		}
	}

	if s.config.SupportEvents {
		capabilities.Events = &EventCapabilities{
			XAddr:                         baseURL + "/events_service",
			WSSubscriptionPolicySupport:   false,
			WSPullPointSupport:            false,
			WSPausableSubscriptionSupport: false,
		}
	}

	return &GetCapabilitiesResponse{
		Capabilities: capabilities,
	}, nil
}

// HandleGetSystemDateAndTime handles GetSystemDateAndTime request.
func (s *Server) HandleGetSystemDateAndTime(body interface{}) (interface{}, error) {
	now := time.Now().UTC()

	return &soap.GetSystemDateAndTimeResponse{
		SystemDateAndTime: soap.SystemDateAndTime{
			DateTimeType:    "NTP",
			DaylightSavings: false,
			TimeZone: soap.TimeZone{
				TZ: "UTC",
			},
			UTCDateTime:   soap.ToDateTime(now),
			LocalDateTime: soap.ToDateTime(now.Local()),
		},
	}, nil
}

// HandleGetServices handles GetServices request.
func (s *Server) HandleGetServices(body interface{}) (interface{}, error) {
	host := s.config.Host
	if host == defaultHost || host == "" {
		host = defaultHostname
	}

	baseURL := fmt.Sprintf("http://%s:%d%s", host, s.config.Port, s.config.BasePath)

	services := []Service{
		{
			Namespace: "http://www.onvif.org/ver10/device/wsdl",
			XAddr:     baseURL + "/device_service",
			Version:   Version{Major: 2, Minor: 5}, //nolint:mnd // ONVIF version
		},
		{
			Namespace: "http://www.onvif.org/ver10/media/wsdl",
			XAddr:     baseURL + "/media_service",
			Version:   Version{Major: 2, Minor: 5}, //nolint:mnd // ONVIF version
		},
	}

	if s.config.SupportPTZ {
		services = append(services, Service{
			Namespace: "http://www.onvif.org/ver20/ptz/wsdl",
			XAddr:     baseURL + "/ptz_service",
			Version:   Version{Major: 2, Minor: 5}, //nolint:mnd // ONVIF version
		})
	}

	if s.config.SupportImaging {
		services = append(services, Service{
			Namespace: "http://www.onvif.org/ver20/imaging/wsdl",
			XAddr:     baseURL + "/imaging_service",
			Version:   Version{Major: 2, Minor: 5}, //nolint:mnd // ONVIF version
		})
	}

	return &GetServicesResponse{
		Service: services,
	}, nil
}

// HandleSystemReboot handles SystemReboot request.
func (s *Server) HandleSystemReboot(body interface{}) (interface{}, error) {
	return &SystemRebootResponse{
		Message: "Device rebooting",
	}, nil
}
