package server

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/apppicker"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/bluez"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/brightness"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/clipboard"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/cups"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/dwl"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/evdev"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/extworkspace"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/freedesktop"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/loginctl"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/network"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wayland"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlcontext"
	"github.com/AvengeMedia/DankMaterialShell/core/internal/server/wlroutput"
	"github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap"
)

const APIVersion = 24

var CLIVersion = "dev"

type Capabilities struct {
	Capabilities []string `json:"capabilities"`
}

type ServerInfo struct {
	APIVersion   int      `json:"apiVersion"`
	CLIVersion   string   `json:"cliVersion,omitempty"`
	Capabilities []string `json:"capabilities"`
}

type ServiceEvent struct {
	Service string `json:"service"`
	Data    any    `json:"data"`
}

var networkManager *network.Manager
var loginctlManager *loginctl.Manager
var freedesktopManager *freedesktop.Manager
var waylandManager *wayland.Manager
var bluezManager *bluez.Manager
var appPickerManager *apppicker.Manager
var cupsManager *cups.Manager
var dwlManager *dwl.Manager
var extWorkspaceManager *extworkspace.Manager
var brightnessManager *brightness.Manager
var wlrOutputManager *wlroutput.Manager
var evdevManager *evdev.Manager
var clipboardManager *clipboard.Manager
var wlContext *wlcontext.SharedContext

var capabilitySubscribers syncmap.Map[string, chan ServerInfo]
var cupsSubscribers syncmap.Map[string, bool]
var cupsSubscriberCount atomic.Int32
var extWorkspaceAvailable atomic.Bool
var extWorkspaceInitMutex sync.Mutex

func getSocketDir() string {
	if runtime := os.Getenv("XDG_RUNTIME_DIR"); runtime != "" {
		return runtime
	}

	if os.Getuid() == 0 {
		if _, err := os.Stat("/run"); err == nil {
			return "/run/dankdots"
		}
		return "/var/run/dankdots"
	}

	return os.TempDir()
}

func GetSocketPath() string {
	return filepath.Join(getSocketDir(), fmt.Sprintf("danklinux-%d.sock", os.Getpid()))
}

func FindSocket() (string, error) {
	dir := getSocketDir()
	entries, err := os.ReadDir(dir)
	if err != nil {
		return "", err
	}

	for _, entry := range entries {
		if strings.HasPrefix(entry.Name(), "danklinux-") && strings.HasSuffix(entry.Name(), ".sock") {
			return filepath.Join(dir, entry.Name()), nil
		}
	}
	return "", fmt.Errorf("no dms socket found")
}

func cleanupStaleSockets() {
	dir := getSocketDir()
	entries, err := os.ReadDir(dir)
	if err != nil {
		return
	}

	for _, entry := range entries {
		if !strings.HasPrefix(entry.Name(), "danklinux-") || !strings.HasSuffix(entry.Name(), ".sock") {
			continue
		}

		pidStr := strings.TrimPrefix(entry.Name(), "danklinux-")
		pidStr = strings.TrimSuffix(pidStr, ".sock")
		pid, err := strconv.Atoi(pidStr)
		if err != nil {
			continue
		}

		process, err := os.FindProcess(pid)
		if err != nil {
			socketPath := filepath.Join(dir, entry.Name())
			os.Remove(socketPath)
			log.Debugf("Removed stale socket: %s", socketPath)
			continue
		}

		err = process.Signal(syscall.Signal(0))
		if err != nil {
			socketPath := filepath.Join(dir, entry.Name())
			os.Remove(socketPath)
			log.Debugf("Removed stale socket: %s", socketPath)
		}
	}
}

func InitializeNetworkManager() error {
	manager, err := network.NewManager()
	if err != nil {
		log.Warnf("Failed to initialize network manager: %v", err)
		return err
	}

	networkManager = manager

	log.Info("Network manager initialized")
	return nil
}

func InitializeLoginctlManager() error {
	manager, err := loginctl.NewManager()
	if err != nil {
		log.Warnf("Failed to initialize loginctl manager: %v", err)
		return err
	}

	loginctlManager = manager

	log.Info("Loginctl manager initialized")
	return nil
}

func InitializeFreedeskManager() error {
	manager, err := freedesktop.NewManager()
	if err != nil {
		log.Warnf("Failed to initialize freedesktop manager: %v", err)
		return err
	}

	freedesktopManager = manager

	log.Info("Freedesktop manager initialized")
	return nil
}

func InitializeWaylandManager() error {
	log.Info("Attempting to initialize Wayland gamma control...")

	if wlContext == nil {
		ctx, err := wlcontext.New()
		if err != nil {
			log.Errorf("Failed to create shared Wayland context: %v", err)
			return err
		}
		wlContext = ctx
	}

	config := wayland.DefaultConfig()
	manager, err := wayland.NewManager(wlContext.Display(), config)
	if err != nil {
		log.Errorf("Failed to initialize wayland manager: %v", err)
		return err
	}

	waylandManager = manager

	log.Info("Wayland gamma control initialized successfully")
	return nil
}

func InitializeBluezManager() error {
	manager, err := bluez.NewManager()
	if err != nil {
		log.Warnf("Failed to initialize bluez manager: %v", err)
		return err
	}

	bluezManager = manager

	log.Info("Bluez manager initialized")
	return nil
}

func InitializeAppPickerManager() error {
	manager := apppicker.NewManager()
	appPickerManager = manager
	log.Info("AppPicker manager initialized")
	return nil
}

func InitializeCupsManager() error {
	manager, err := cups.NewManager()
	if err != nil {
		log.Warnf("Failed to initialize cups manager: %v", err)
		return err
	}

	cupsManager = manager

	log.Info("CUPS manager initialized")
	return nil
}

func InitializeDwlManager() error {
	log.Info("Attempting to initialize DWL IPC...")

	if wlContext == nil {
		ctx, err := wlcontext.New()
		if err != nil {
			log.Errorf("Failed to create shared Wayland context: %v", err)
			return err
		}
		wlContext = ctx
	}

	manager, err := dwl.NewManager(wlContext.Display())
	if err != nil {
		log.Debug("Failed to initialize dwl manager: %v", err)
		return err
	}

	dwlManager = manager

	log.Info("DWL IPC initialized successfully")
	return nil
}

func InitializeBrightnessManager() error {
	manager, err := brightness.NewManager()
	if err != nil {
		log.Warnf("Failed to initialize brightness manager: %v", err)
		return err
	}

	brightnessManager = manager

	log.Info("Brightness manager initialized")
	return nil
}

func InitializeExtWorkspaceManager() error {
	log.Info("Attempting to initialize ExtWorkspace...")

	if wlContext == nil {
		ctx, err := wlcontext.New()
		if err != nil {
			log.Errorf("Failed to create shared Wayland context: %v", err)
			return err
		}
		wlContext = ctx
	}

	manager, err := extworkspace.NewManager(wlContext.Display())
	if err != nil {
		log.Debug("Failed to initialize extworkspace manager: %v", err)
		return err
	}

	extWorkspaceManager = manager

	log.Info("ExtWorkspace initialized successfully")
	return nil
}

func InitializeWlrOutputManager() error {
	log.Info("Attempting to initialize WlrOutput management...")

	if wlContext == nil {
		ctx, err := wlcontext.New()
		if err != nil {
			log.Errorf("Failed to create shared Wayland context: %v", err)
			return err
		}
		wlContext = ctx
	}

	manager, err := wlroutput.NewManager(wlContext.Display())
	if err != nil {
		log.Debug("Failed to initialize wlroutput manager: %v", err)
		return err
	}

	wlrOutputManager = manager

	log.Info("WlrOutput management initialized successfully")
	return nil
}

func InitializeEvdevManager() error {
	manager, err := evdev.InitializeManager()
	if err != nil {
		log.Warnf("Failed to initialize evdev manager: %v", err)
		return err
	}

	evdevManager = manager

	log.Info("Evdev manager initialized")
	return nil
}

func InitializeClipboardManager() error {
	log.Info("Attempting to initialize clipboard manager...")

	if wlContext == nil {
		ctx, err := wlcontext.New()
		if err != nil {
			log.Errorf("Failed to create shared Wayland context: %v", err)
			return err
		}
		wlContext = ctx
	}

	config := clipboard.LoadConfig()
	manager, err := clipboard.NewManager(wlContext, config)
	if err != nil {
		log.Errorf("Failed to initialize clipboard manager: %v", err)
		return err
	}

	clipboardManager = manager

	log.Info("Clipboard manager initialized successfully")
	return nil
}

func handleConnection(conn net.Conn) {
	defer conn.Close()

	caps := getCapabilities()
	capsData, _ := json.Marshal(caps)
	conn.Write(capsData)
	conn.Write([]byte("\n"))
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		line := scanner.Bytes()

		var req models.Request
		if err := json.Unmarshal(line, &req); err != nil {
			log.Warnf("handleConnection: Failed to unmarshal JSON: %v, line: %s", err, string(line))
			models.RespondError(conn, 0, "invalid json")
			continue
		}

		go RouteRequest(conn, req)
	}
}

func getCapabilities() Capabilities {
	caps := []string{"plugins"}

	if networkManager != nil {
		caps = append(caps, "network")
	}

	if loginctlManager != nil {
		caps = append(caps, "loginctl")
	}

	if freedesktopManager != nil {
		caps = append(caps, "freedesktop")
	}

	if waylandManager != nil {
		caps = append(caps, "gamma")
	}

	if bluezManager != nil {
		caps = append(caps, "bluetooth")
	}

	if appPickerManager != nil {
		caps = append(caps, "browser")
	}

	if cupsManager != nil {
		caps = append(caps, "cups")
	}

	if dwlManager != nil {
		caps = append(caps, "dwl")
	}

	if extWorkspaceAvailable.Load() {
		caps = append(caps, "extworkspace")
	}

	if brightnessManager != nil {
		caps = append(caps, "brightness")
	}

	if wlrOutputManager != nil {
		caps = append(caps, "wlroutput")
	}

	if evdevManager != nil {
		caps = append(caps, "evdev")
	}

	if clipboardManager != nil {
		caps = append(caps, "clipboard")
	}

	return Capabilities{Capabilities: caps}
}

func getServerInfo() ServerInfo {
	caps := []string{"plugins"}

	if networkManager != nil {
		caps = append(caps, "network")
	}

	if loginctlManager != nil {
		caps = append(caps, "loginctl")
	}

	if freedesktopManager != nil {
		caps = append(caps, "freedesktop")
	}

	if waylandManager != nil {
		caps = append(caps, "gamma")
	}

	if bluezManager != nil {
		caps = append(caps, "bluetooth")
	}

	if appPickerManager != nil {
		caps = append(caps, "browser")
	}

	if cupsManager != nil {
		caps = append(caps, "cups")
	}

	if dwlManager != nil {
		caps = append(caps, "dwl")
	}

	if extWorkspaceAvailable.Load() {
		caps = append(caps, "extworkspace")
	}

	if brightnessManager != nil {
		caps = append(caps, "brightness")
	}

	if wlrOutputManager != nil {
		caps = append(caps, "wlroutput")
	}

	if evdevManager != nil {
		caps = append(caps, "evdev")
	}

	if clipboardManager != nil {
		caps = append(caps, "clipboard")
	}

	return ServerInfo{
		APIVersion:   APIVersion,
		CLIVersion:   CLIVersion,
		Capabilities: caps,
	}
}

func notifyCapabilityChange() {
	info := getServerInfo()
	capabilitySubscribers.Range(func(key string, ch chan ServerInfo) bool {
		select {
		case ch <- info:
		default:
		}
		return true
	})
}

func handleSubscribe(conn net.Conn, req models.Request) {
	clientID := fmt.Sprintf("meta-client-%p", conn)

	var services []string
	if servicesParam, ok := models.Get[[]any](req, "services"); ok {
		for _, s := range servicesParam {
			if str, ok := s.(string); ok {
				services = append(services, str)
			}
		}
	}

	if len(services) == 0 {
		services = []string{"all"}
	}

	subscribeAll := false
	for _, s := range services {
		if s == "all" {
			subscribeAll = true
			break
		}
	}

	var wg sync.WaitGroup
	eventChan := make(chan ServiceEvent, 256)
	stopChan := make(chan struct{})

	capChan := make(chan ServerInfo, 64)
	capabilitySubscribers.Store(clientID+"-capabilities", capChan)

	wg.Add(1)
	go func() {
		defer wg.Done()
		defer capabilitySubscribers.Delete(clientID + "-capabilities")

		for {
			select {
			case info, ok := <-capChan:
				if !ok {
					return
				}
				select {
				case eventChan <- ServiceEvent{Service: "server", Data: info}:
				case <-stopChan:
					return
				}
			case <-stopChan:
				return
			}
		}
	}()

	shouldSubscribe := func(service string) bool {
		if subscribeAll {
			return true
		}
		for _, s := range services {
			if s == service {
				return true
			}
		}
		return false
	}

	if shouldSubscribe("network") && networkManager != nil {
		wg.Add(1)
		netChan := networkManager.Subscribe(clientID + "-network")
		go func() {
			defer wg.Done()
			defer networkManager.Unsubscribe(clientID + "-network")

			initialState := networkManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "network", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-netChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "network", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("network.credentials") && networkManager != nil {
		wg.Add(1)
		credChan := networkManager.SubscribeCredentials(clientID + "-credentials")
		go func() {
			defer wg.Done()
			defer networkManager.UnsubscribeCredentials(clientID + "-credentials")

			for {
				select {
				case prompt, ok := <-credChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "network.credentials", Data: prompt}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("loginctl") && loginctlManager != nil {
		wg.Add(1)
		loginChan := loginctlManager.Subscribe(clientID + "-loginctl")
		go func() {
			defer wg.Done()
			defer loginctlManager.Unsubscribe(clientID + "-loginctl")

			initialState := loginctlManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "loginctl", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-loginChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "loginctl", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("freedesktop") && freedesktopManager != nil {
		wg.Add(1)
		freedesktopChan := freedesktopManager.Subscribe(clientID + "-freedesktop")
		go func() {
			defer wg.Done()
			defer freedesktopManager.Unsubscribe(clientID + "-freedesktop")

			initialState := freedesktopManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "freedesktop", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-freedesktopChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "freedesktop", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("freedesktop.screensaver") && freedesktopManager != nil {
		wg.Add(1)
		screensaverChan := freedesktopManager.SubscribeScreensaver(clientID + "-screensaver")
		go func() {
			defer wg.Done()
			defer freedesktopManager.UnsubscribeScreensaver(clientID + "-screensaver")

			initialState := freedesktopManager.GetScreensaverState()
			select {
			case eventChan <- ServiceEvent{Service: "freedesktop.screensaver", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-screensaverChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "freedesktop.screensaver", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("gamma") && waylandManager != nil {
		wg.Add(1)
		waylandChan := waylandManager.Subscribe(clientID + "-gamma")
		go func() {
			defer wg.Done()
			defer waylandManager.Unsubscribe(clientID + "-gamma")

			initialState := waylandManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "gamma", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-waylandChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "gamma", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("bluetooth") && bluezManager != nil {
		wg.Add(1)
		bluezChan := bluezManager.Subscribe(clientID + "-bluetooth")
		go func() {
			defer wg.Done()
			defer bluezManager.Unsubscribe(clientID + "-bluetooth")

			initialState := bluezManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "bluetooth", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-bluezChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "bluetooth", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("bluetooth.pairing") && bluezManager != nil {
		wg.Add(1)
		pairingChan := bluezManager.SubscribePairing(clientID + "-pairing")
		go func() {
			defer wg.Done()
			defer bluezManager.UnsubscribePairing(clientID + "-pairing")

			for {
				select {
				case prompt, ok := <-pairingChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "bluetooth.pairing", Data: prompt}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("browser") && appPickerManager != nil {
		wg.Add(1)
		appPickerChan := appPickerManager.Subscribe(clientID + "-browser")
		go func() {
			defer wg.Done()
			defer appPickerManager.Unsubscribe(clientID + "-browser")

			for {
				select {
				case event, ok := <-appPickerChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "browser.open_requested", Data: event}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("cups") {
		cupsSubscribers.Store(clientID+"-cups", true)
		count := cupsSubscriberCount.Add(1)

		if count == 1 {
			if err := InitializeCupsManager(); err != nil {
				log.Warnf("Failed to initialize CUPS manager for subscription: %v", err)
			} else {
				notifyCapabilityChange()
			}
		}

		if cupsManager != nil {
			wg.Add(1)
			cupsChan := cupsManager.Subscribe(clientID + "-cups")
			go func() {
				defer wg.Done()
				defer func() {
					cupsManager.Unsubscribe(clientID + "-cups")
					cupsSubscribers.Delete(clientID + "-cups")
					count := cupsSubscriberCount.Add(-1)

					if count == 0 {
						log.Info("Last CUPS subscriber disconnected, shutting down CUPS manager")
						if cupsManager != nil {
							cupsManager.Close()
							cupsManager = nil
							notifyCapabilityChange()
						}
					}
				}()

				initialState := cupsManager.GetState()
				select {
				case eventChan <- ServiceEvent{Service: "cups", Data: initialState}:
				case <-stopChan:
					return
				}

				for {
					select {
					case state, ok := <-cupsChan:
						if !ok {
							return
						}
						select {
						case eventChan <- ServiceEvent{Service: "cups", Data: state}:
						case <-stopChan:
							return
						}
					case <-stopChan:
						return
					}
				}
			}()
		}
	}

	if shouldSubscribe("dwl") && dwlManager != nil {
		wg.Add(1)
		dwlChan := dwlManager.Subscribe(clientID + "-dwl")
		go func() {
			defer wg.Done()
			defer dwlManager.Unsubscribe(clientID + "-dwl")

			initialState := dwlManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "dwl", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-dwlChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "dwl", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("extworkspace") {
		if extWorkspaceManager == nil && extWorkspaceAvailable.Load() {
			extWorkspaceInitMutex.Lock()
			if extWorkspaceManager == nil {
				if err := InitializeExtWorkspaceManager(); err != nil {
					log.Warnf("Failed to initialize ExtWorkspace manager for subscription: %v", err)
				}
			}
			extWorkspaceInitMutex.Unlock()
		}

		if extWorkspaceManager != nil {
			wg.Add(1)
			extWorkspaceChan := extWorkspaceManager.Subscribe(clientID + "-extworkspace")
			go func() {
				defer wg.Done()
				defer extWorkspaceManager.Unsubscribe(clientID + "-extworkspace")

				initialState := extWorkspaceManager.GetState()
				select {
				case eventChan <- ServiceEvent{Service: "extworkspace", Data: initialState}:
				case <-stopChan:
					return
				}

				for {
					select {
					case state, ok := <-extWorkspaceChan:
						if !ok {
							return
						}
						select {
						case eventChan <- ServiceEvent{Service: "extworkspace", Data: state}:
						case <-stopChan:
							return
						}
					case <-stopChan:
						return
					}
				}
			}()
		}
	}

	if shouldSubscribe("brightness") && brightnessManager != nil {
		wg.Add(2)
		brightnessStateChan := brightnessManager.Subscribe(clientID + "-brightness-state")
		brightnessUpdateChan := brightnessManager.SubscribeUpdates(clientID + "-brightness-updates")

		go func() {
			defer wg.Done()
			defer brightnessManager.Unsubscribe(clientID + "-brightness-state")

			initialState := brightnessManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "brightness", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-brightnessStateChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "brightness", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()

		go func() {
			defer wg.Done()
			defer brightnessManager.UnsubscribeUpdates(clientID + "-brightness-updates")

			for {
				select {
				case update, ok := <-brightnessUpdateChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "brightness.update", Data: update}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("wlroutput") && wlrOutputManager != nil {
		wg.Add(1)
		wlrOutputChan := wlrOutputManager.Subscribe(clientID + "-wlroutput")
		go func() {
			defer wg.Done()
			defer wlrOutputManager.Unsubscribe(clientID + "-wlroutput")

			initialState := wlrOutputManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "wlroutput", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-wlrOutputChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "wlroutput", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("evdev") && evdevManager != nil {
		wg.Add(1)
		evdevChan := evdevManager.Subscribe(clientID + "-evdev")
		go func() {
			defer wg.Done()
			defer evdevManager.Unsubscribe(clientID + "-evdev")

			initialState := evdevManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "evdev", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-evdevChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "evdev", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	if shouldSubscribe("clipboard") && clipboardManager != nil {
		wg.Add(1)
		clipboardChan := clipboardManager.Subscribe(clientID + "-clipboard")
		go func() {
			defer wg.Done()
			defer clipboardManager.Unsubscribe(clientID + "-clipboard")

			initialState := clipboardManager.GetState()
			select {
			case eventChan <- ServiceEvent{Service: "clipboard", Data: initialState}:
			case <-stopChan:
				return
			}

			for {
				select {
				case state, ok := <-clipboardChan:
					if !ok {
						return
					}
					select {
					case eventChan <- ServiceEvent{Service: "clipboard", Data: state}:
					case <-stopChan:
						return
					}
				case <-stopChan:
					return
				}
			}
		}()
	}

	go func() {
		wg.Wait()
		close(eventChan)
	}()

	info := getServerInfo()
	if err := json.NewEncoder(conn).Encode(models.Response[ServiceEvent]{
		ID:     req.ID,
		Result: &ServiceEvent{Service: "server", Data: info},
	}); err != nil {
		close(stopChan)
		return
	}

	for event := range eventChan {
		if err := json.NewEncoder(conn).Encode(models.Response[ServiceEvent]{
			ID:     req.ID,
			Result: &event,
		}); err != nil {
			close(stopChan)
			return
		}
	}
}

func cleanupManagers() {
	if networkManager != nil {
		networkManager.Close()
	}
	if loginctlManager != nil {
		loginctlManager.Close()
	}
	if freedesktopManager != nil {
		freedesktopManager.Close()
	}
	if waylandManager != nil {
		waylandManager.Close()
	}
	if bluezManager != nil {
		bluezManager.Close()
	}
	if appPickerManager != nil {
		appPickerManager.Close()
	}
	if cupsManager != nil {
		cupsManager.Close()
	}
	if dwlManager != nil {
		dwlManager.Close()
	}
	if extWorkspaceManager != nil {
		extWorkspaceManager.Close()
	}
	if brightnessManager != nil {
		brightnessManager.Close()
	}
	if wlrOutputManager != nil {
		wlrOutputManager.Close()
	}
	if evdevManager != nil {
		evdevManager.Close()
	}
	if clipboardManager != nil {
		clipboardManager.Close()
	}
	if wlContext != nil {
		wlContext.Close()
	}
}

func Start(printDocs bool) error {
	cleanupStaleSockets()

	socketPath := GetSocketPath()
	os.Remove(socketPath)

	listener, err := net.Listen("unix", socketPath)
	if err != nil {
		return err
	}
	defer listener.Close()
	defer cleanupManagers()

	log.Infof("DMS API Server listening on: %s", socketPath)
	log.Infof("API Version: %d", APIVersion)
	log.Info("Protocol: JSON over Unix socket")
	log.Info("Request format: {\"id\": <any>, \"method\": \"...\", \"params\": {...}}")
	log.Info("Response format: {\"id\": <any>, \"result\": {...}} or {\"id\": <any>, \"error\": \"...\"}")
	log.Info("")
	if printDocs {
		log.Info("Available methods:")
		log.Info("  ping          - Test connection")
		log.Info("  getServerInfo - Get server info (API version and capabilities)")
		log.Info("  subscribe     - Subscribe to multiple services (params: services [default: all])")
		log.Info("Plugins:")
		log.Info(" plugins.list                - List all plugins")
		log.Info(" plugins.listInstalled       - List installed plugins")
		log.Info(" plugins.install             - Install plugin (params: name)")
		log.Info(" plugins.uninstall           - Uninstall plugin (params: name)")
		log.Info(" plugins.update              - Update plugin (params: name)")
		log.Info(" plugins.search              - Search plugins (params: query, category?, compositor?, capability?)")
		log.Info("Network:")
		log.Info(" network.getState            - Get current network state")
		log.Info(" network.wifi.scan           - Scan for WiFi networks (params: device?)")
		log.Info(" network.wifi.networks       - Get WiFi network list")
		log.Info(" network.wifi.connect        - Connect to WiFi (params: ssid, password?, username?, device?, eapMethod?, phase2Auth?, caCertPath?, clientCertPath?, privateKeyPath?, useSystemCACerts?)")
		log.Info(" network.wifi.disconnect     - Disconnect WiFi (params: device?)")
		log.Info(" network.wifi.forget         - Forget network (params: ssid)")
		log.Info(" network.wifi.toggle         - Toggle WiFi radio")
		log.Info(" network.wifi.enable         - Enable WiFi")
		log.Info(" network.wifi.disable        - Disable WiFi")
		log.Info(" network.wifi.setAutoconnect - Set network autoconnect (params: ssid, autoconnect)")
		log.Info(" network.ethernet.connect    - Connect Ethernet")
		log.Info(" network.ethernet.connect.config - Connect Ethernet to a specific configuration")
		log.Info(" network.ethernet.disconnect - Disconnect Ethernet")
		log.Info(" network.vpn.profiles        - List VPN profiles")
		log.Info(" network.vpn.active          - List active VPN connections")
		log.Info(" network.vpn.connect         - Connect VPN (params: uuidOrName|name|uuid, singleActive?)")
		log.Info(" network.vpn.disconnect      - Disconnect VPN (params: uuidOrName|name|uuid)")
		log.Info(" network.vpn.disconnectAll   - Disconnect all VPNs")
		log.Info(" network.vpn.clearCredentials - Clear saved VPN credentials (params: uuidOrName|name|uuid)")
		log.Info(" network.vpn.plugins         - List available VPN plugins")
		log.Info(" network.vpn.import          - Import VPN from file (params: file|path, name?)")
		log.Info(" network.vpn.getConfig       - Get VPN configuration (params: uuid|name|uuidOrName)")
		log.Info(" network.vpn.updateConfig    - Update VPN configuration (params: uuid, name?, autoconnect?, data?)")
		log.Info(" network.vpn.delete          - Delete VPN connection (params: uuid|name|uuidOrName)")
		log.Info(" network.preference.set      - Set preference (params: preference [auto|wifi|ethernet])")
		log.Info(" network.info                - Get network info (params: ssid)")
		log.Info(" network.credentials.submit  - Submit credentials for prompt (params: token, secrets, save?)")
		log.Info(" network.credentials.cancel  - Cancel credential prompt (params: token)")
		log.Info(" network.subscribe           - Subscribe to network state changes (streaming)")
		log.Info("Loginctl:")
		log.Info(" loginctl.getState           - Get current session state")
		log.Info(" loginctl.lock               - Lock session")
		log.Info(" loginctl.unlock             - Unlock session")
		log.Info(" loginctl.activate           - Activate session")
		log.Info(" loginctl.setIdleHint        - Set idle hint (params: idle)")
		log.Info(" loginctl.setLockBeforeSuspend - Set lock before suspend (params: enabled)")
		log.Info(" loginctl.setSleepInhibitorEnabled - Enable/disable sleep inhibitor (params: enabled)")
		log.Info(" loginctl.lockerReady        - Signal locker UI is ready (releases sleep inhibitor)")
		log.Info(" loginctl.terminate          - Terminate session")
		log.Info(" loginctl.subscribe          - Subscribe to session state changes (streaming)")
		log.Info("Freedesktop:")
		log.Info(" freedesktop.getState                  - Get accounts & settings state")
		log.Info(" freedesktop.accounts.setIconFile      - Set profile icon (params: path)")
		log.Info(" freedesktop.accounts.setRealName      - Set real name (params: name)")
		log.Info(" freedesktop.accounts.setEmail         - Set email (params: email)")
		log.Info(" freedesktop.accounts.setLanguage      - Set language (params: language)")
		log.Info(" freedesktop.accounts.setLocation      - Set location (params: location)")
		log.Info(" freedesktop.accounts.getUserIconFile  - Get user icon (params: username)")
		log.Info(" freedesktop.settings.getColorScheme   - Get color scheme")
		log.Info(" freedesktop.settings.setIconTheme     - Set icon theme (params: iconTheme)")
		log.Info("Wayland:")
		log.Info(" wayland.gamma.getState                - Get current gamma control state")
		log.Info(" wayland.gamma.setTemperature          - Set temperature range (params: low, high)")
		log.Info(" wayland.gamma.setLocation             - Set location (params: latitude, longitude)")
		log.Info(" wayland.gamma.setManualTimes          - Set manual times (params: sunrise, sunset)")
		log.Info(" wayland.gamma.setGamma                - Set gamma value (params: gamma)")
		log.Info(" wayland.gamma.setEnabled              - Enable/disable gamma control (params: enabled)")
		log.Info(" wayland.gamma.subscribe               - Subscribe to gamma state changes (streaming)")
		log.Info("Bluetooth:")
		log.Info(" bluetooth.getState                    - Get current bluetooth state")
		log.Info(" bluetooth.startDiscovery              - Start device discovery")
		log.Info(" bluetooth.stopDiscovery               - Stop device discovery")
		log.Info(" bluetooth.setPowered                  - Set adapter power state (params: powered)")
		log.Info(" bluetooth.pair                        - Pair with device (params: device)")
		log.Info(" bluetooth.connect                     - Connect to device (params: device)")
		log.Info(" bluetooth.disconnect                  - Disconnect from device (params: device)")
		log.Info(" bluetooth.remove                      - Remove/unpair device (params: device)")
		log.Info(" bluetooth.trust                       - Trust device (params: device)")
		log.Info(" bluetooth.untrust                     - Untrust device (params: device)")
		log.Info(" bluetooth.pairing.submit              - Submit pairing response (params: token, secrets?, accept?)")
		log.Info(" bluetooth.pairing.cancel              - Cancel pairing prompt (params: token)")
		log.Info(" bluetooth.subscribe                   - Subscribe to bluetooth state changes (streaming)")
		log.Info("CUPS:")
		log.Info(" cups.getPrinters                      - Get printers list")
		log.Info(" cups.getJobs                          - Get non-completed jobs list (params: printerName)")
		log.Info(" cups.pausePrinter                     - Pause printer (params: printerName)")
		log.Info(" cups.resumePrinter                    - Resume printer (params: printerName)")
		log.Info(" cups.cancelJob                        - Cancel job (params: printerName, jobID)")
		log.Info(" cups.purgeJobs                        - Cancel all jobs (params: printerName)")
		log.Info("DWL:")
		log.Info(" dwl.getState                          - Get current dwl state (tags, windows, layouts, keyboard)")
		log.Info(" dwl.setTags                           - Set active tags (params: output, tagmask, toggleTagset)")
		log.Info(" dwl.setClientTags                     - Set focused client tags (params: output, andTags, xorTags)")
		log.Info(" dwl.setLayout                         - Set layout (params: output, index)")
		log.Info(" dwl.subscribe                         - Subscribe to dwl state changes (streaming)")
		log.Info("   Output state includes:")
		log.Info("     - tags         : Tag states (active, clients, focused)")
		log.Info("     - layoutSymbol : Current layout name")
		log.Info("     - title        : Focused window title")
		log.Info("     - appId        : Focused window app ID")
		log.Info("     - kbLayout     : Current keyboard layout")
		log.Info("     - keymode      : Current keybind mode")
		log.Info("ExtWorkspace:")
		log.Info(" extworkspace.getState                 - Get current workspace state (groups, workspaces)")
		log.Info(" extworkspace.activateWorkspace        - Activate workspace (params: groupID, workspaceID)")
		log.Info(" extworkspace.deactivateWorkspace      - Deactivate workspace (params: groupID, workspaceID)")
		log.Info(" extworkspace.removeWorkspace          - Remove workspace (params: groupID, workspaceID)")
		log.Info(" extworkspace.createWorkspace          - Create workspace (params: groupID, name)")
		log.Info(" extworkspace.subscribe                - Subscribe to workspace state changes (streaming)")
		log.Info("Brightness:")
		log.Info(" brightness.getState                   - Get current brightness state for all devices")
		log.Info(" brightness.setBrightness              - Set device brightness (params: device, percent)")
		log.Info(" brightness.increment                  - Increment device brightness (params: device, step?)")
		log.Info(" brightness.decrement                  - Decrement device brightness (params: device, step?)")
		log.Info(" brightness.rescan                     - Rescan for brightness devices (e.g., after plugging in monitor)")
		log.Info(" brightness.subscribe                  - Subscribe to brightness state changes (streaming)")
		log.Info("   Subscription events:")
		log.Info("     - brightness       : Full device list (on rescan, DDC discovery, device changes)")
		log.Info("     - brightness.update: Single device update (on brightness change for efficiency)")
		log.Info("WlrOutput:")
		log.Info(" wlroutput.getState                    - Get current output configuration state")
		log.Info(" wlroutput.applyConfiguration          - Apply output configuration (params: heads)")
		log.Info(" wlroutput.testConfiguration           - Test output configuration without applying (params: heads)")
		log.Info(" wlroutput.subscribe                   - Subscribe to output state changes (streaming)")
		log.Info("   Head configuration params:")
		log.Info("     - name         : Output name (required)")
		log.Info("     - enabled      : Enable/disable output (required)")
		log.Info("     - modeId       : Mode ID from available modes (optional)")
		log.Info("     - customMode   : Custom mode {width, height, refresh} (optional)")
		log.Info("     - position     : Position {x, y} (optional)")
		log.Info("     - transform    : Transform value (optional)")
		log.Info("     - scale        : Scale value (optional)")
		log.Info("     - adaptiveSync : Adaptive sync state (optional)")
		log.Info("Evdev:")
		log.Info(" evdev.getState                        - Get current evdev state (caps lock)")
		log.Info(" evdev.subscribe                       - Subscribe to evdev state changes (streaming)")
		log.Info("Clipboard:")
		log.Info(" clipboard.getState                    - Get clipboard state (enabled, history, current)")
		log.Info(" clipboard.getHistory                  - Get clipboard history with previews")
		log.Info(" clipboard.getEntry                    - Get full entry by ID (params: id)")
		log.Info(" clipboard.deleteEntry                 - Delete entry by ID (params: id)")
		log.Info(" clipboard.clearHistory                - Clear all clipboard history")
		log.Info(" clipboard.copy                        - Copy text to clipboard (params: text)")
		log.Info(" clipboard.paste                       - Get current clipboard text")
		log.Info(" clipboard.search                      - Search history (params: query?, mimeType?, isImage?, limit?, offset?, before?, after?)")
		log.Info(" clipboard.getConfig                   - Get clipboard configuration")
		log.Info(" clipboard.setConfig                   - Set configuration (params: maxHistory?, maxEntrySize?, autoClearDays?, clearAtStartup?)")
		log.Info(" clipboard.subscribe                   - Subscribe to clipboard state changes (streaming)")
		log.Info("")
	}
	log.Info("Initializing managers...")
	log.Info("")

	go func() {
		ticker := time.NewTicker(30 * time.Second)
		defer ticker.Stop()

		if err := InitializeNetworkManager(); err != nil {
			log.Warnf("Network manager unavailable: %v", err)
		} else {
			notifyCapabilityChange()
			return
		}

		for range ticker.C {
			if networkManager != nil {
				return
			}
			if err := InitializeNetworkManager(); err == nil {
				log.Info("Network manager initialized")
				notifyCapabilityChange()
				return
			}
		}
	}()

	go func() {
		if err := InitializeLoginctlManager(); err != nil {
			log.Warnf("Loginctl manager unavailable: %v", err)
		} else {
			notifyCapabilityChange()
		}
	}()

	go func() {
		if err := InitializeFreedeskManager(); err != nil {
			log.Warnf("Freedesktop manager unavailable: %v", err)
		} else if freedesktopManager != nil {
			freedesktopManager.NotifySubscribers()
			notifyCapabilityChange()
		}
	}()

	if err := InitializeWaylandManager(); err != nil {
		log.Warnf("Wayland manager unavailable: %v", err)
	}

	go func() {
		if err := InitializeBluezManager(); err != nil {
			log.Warnf("Bluez manager unavailable: %v", err)
		} else {
			notifyCapabilityChange()
		}
	}()

	if err := InitializeAppPickerManager(); err != nil {
		log.Debugf("AppPicker manager unavailable: %v", err)
	}

	if err := InitializeDwlManager(); err != nil {
		log.Debugf("DWL manager unavailable: %v", err)
	}

	if extworkspace.CheckCapability() {
		extWorkspaceAvailable.Store(true)
		log.Info("ExtWorkspace capability detected and will be available on subscription")
	} else {
		log.Debug("ExtWorkspace capability not available")
		extWorkspaceAvailable.Store(false)
	}

	if err := InitializeWlrOutputManager(); err != nil {
		log.Debugf("WlrOutput manager unavailable: %v", err)
	}

	fatalErrChan := make(chan error, 1)
	if wlrOutputManager != nil {
		go func() {
			err := <-wlrOutputManager.FatalError()
			fatalErrChan <- fmt.Errorf("WlrOutput fatal error: %w", err)
		}()
	}
	if wlContext != nil {
		go func() {
			err := <-wlContext.FatalError()
			fatalErrChan <- fmt.Errorf("wayland context fatal error: %w", err)
		}()
	}

	go func() {
		if err := InitializeBrightnessManager(); err != nil {
			log.Warnf("Brightness manager unavailable: %v", err)
		} else {
			notifyCapabilityChange()
		}
	}()

	go func() {
		if err := InitializeEvdevManager(); err != nil {
			log.Debugf("Evdev manager unavailable: %v", err)
		} else {
			notifyCapabilityChange()
		}
	}()

	go func() {
		if err := InitializeClipboardManager(); err != nil {
			log.Warnf("Clipboard manager unavailable: %v", err)
		}
		if wlContext != nil {
			wlContext.Start()
			log.Info("Wayland event dispatcher started")
		}
	}()

	log.Info("")
	log.Infof("Ready! Capabilities: %v", getCapabilities().Capabilities)

	listenerErrChan := make(chan error, 1)

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				listenerErrChan <- err
				return
			}
			go handleConnection(conn)
		}
	}()

	select {
	case err := <-listenerErrChan:
		return err
	case err := <-fatalErrChan:
		return err
	}
}
