package client

import (
	"crypto/tls"
	"encoding/json"
	"fikoyt-ajan/internal/config"
	"fikoyt-ajan/internal/desktop"
	"fikoyt-ajan/internal/handlers"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// SocketClient - Socket.IO client using gorilla/websocket
type SocketClient struct {
	config        *config.Config
	mesajHandler  *handlers.MesajHandler
	komutHandler  *handlers.KomutHandler
	sistemHandler *handlers.SistemHandler
	remoteHandler *handlers.RemoteHandler

	conn       *websocket.Conn
	httpClient *http.Client
	bagli      bool
	mu         sync.RWMutex
	kapatCh    chan struct{}
	durumCh    chan string
	writeMu    sync.Mutex

	eventHandlers      map[string]func(data interface{})
	sid                string    // Session ID from Engine.IO
	sonPing            time.Time // Son ping zamanı (timeout kontrolü için)
	manuelYenidenBaglan bool     // Manuel reconnect flag (race condition önleme)
}

// Engine.IO packet types
const (
	engineOpen    = '0'
	engineClose   = '1'
	enginePing    = '2'
	enginePong    = '3'
	engineMessage = '4'
)

// Socket.IO packet types
const (
	socketConnect      = '0'
	socketDisconnect   = '1'
	socketEvent        = '2'
	socketAck          = '3'
	socketConnectError = '4'
)

// EngineIOOpen - Engine.IO open paketi
type EngineIOOpen struct {
	Sid          string   `json:"sid"`
	Upgrades     []string `json:"upgrades"`
	PingInterval int      `json:"pingInterval"`
	PingTimeout  int      `json:"pingTimeout"`
}

// YeniSocketClient - Yeni socket client oluştur
func YeniSocketClient(cfg *config.Config, mh *handlers.MesajHandler, kh *handlers.KomutHandler, sh *handlers.SistemHandler) *SocketClient {
	// TLS config (self-signed için)
	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
	}

	httpClient := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: tlsConfig,
		},
		Timeout: 30 * time.Second,
	}

	// Remote handler oluştur
	pluginDir := "./plugins"
	configDir := "./config"
	currentVersion := "1.0.0"
	updateURL := cfg.SunucuURL + "/fikoyt-api/ajanlar/updates"
	remoteHandler := handlers.NewRemoteHandler(pluginDir, configDir, currentVersion, updateURL)

	sc := &SocketClient{
		config:        cfg,
		mesajHandler:  mh,
		komutHandler:  kh,
		sistemHandler: sh,
		remoteHandler: remoteHandler,
		httpClient:    httpClient,
		kapatCh:       make(chan struct{}),
		durumCh:       make(chan string, 10),
		eventHandlers: make(map[string]func(data interface{})),
	}

	// Remote handler callback'lerini ayarla
	remoteHandler.SetCallbacks(
		// Ekran frame callback (panic recovery ile)
		func(frame *desktop.ScreenFrame) {
			defer func() {
				if r := recover(); r != nil {
					// Panic recovery - sessizce geç
				}
			}()

			// Frame data kontrolü
			if frame == nil || len(frame.Data) == 0 {
				return
			}

			sc.Emit("FikoYT.ajan.remote.screen.frame", map[string]interface{}{
				"ajanId":    cfg.AjanId,
				"data":      frame.Data,
				"width":     frame.Width,
				"height":    frame.Height,
				"format":    frame.Format,
				"timestamp": frame.Timestamp,
				"displayId": frame.DisplayID,
			})
		},
		// Genel event callback (panic recovery ile)
		func(event string, data interface{}) {
			defer func() {
				if r := recover(); r != nil {
					// Panic recovery - sessizce geç
				}
			}()
			sc.Emit("FikoYT.ajan."+event, data)
		},
	)

	// WebRTC callback'lerini ayarla
	remoteHandler.SetWebRTCCallbacks(
		// ICE candidate callback - sunucuya gönder
		func(candidate interface{}) {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("WebRTC ICE gönderiminde panic: %v", r)
				}
			}()
			if err := sc.Emit("FikoYT.ajan.remote.webrtc.ice.ajan", map[string]interface{}{
				"ajanId":    cfg.AjanId,
				"candidate": candidate,
			}); err != nil {
				log.Printf("WebRTC ICE gönderilemedi: %v", err)
			}
		},
		// SDP callback (offer/answer sonrası - gerekirse)
		func(sdp interface{}) {
			// SDP genellikle response olarak döner, bu callback özel durumlar için
			log.Printf("WebRTC SDP callback: %v", sdp)
		},
	)

	return sc
}

// Baglan - Sunucuya bağlan
func (sc *SocketClient) Baglan() error {
	log.Printf("Sunucuya bağlanılıyor: %s", sc.config.SunucuURL)

	// Doğrudan WebSocket bağlantısı kur (polling olmadan)
	err := sc.websocketDirekBaglan()
	if err != nil {
		return fmt.Errorf("WebSocket bağlantı hatası: %v", err)
	}

	return nil
}

// websocketDirekBaglan - Doğrudan WebSocket bağlantısı kur (polling olmadan)
func (sc *SocketClient) websocketDirekBaglan() error {
	baseURL := sc.config.SunucuURL

	// WebSocket URL oluştur
	wsURL := strings.Replace(baseURL, "https://", "wss://", 1)
	wsURL = strings.Replace(wsURL, "http://", "ws://", 1)

	u, err := url.Parse(wsURL)
	if err != nil {
		return err
	}

	u.Path = "/socket.io/"
	q := u.Query()
	q.Set("EIO", "4")
	q.Set("transport", "websocket")
	u.RawQuery = q.Encode()

	log.Printf("WebSocket URL: %s", u.String())

	// TLS config
	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
	}

	dialer := websocket.Dialer{
		TLSClientConfig:  tlsConfig,
		HandshakeTimeout: 30 * time.Second,
	}

	// Header
	header := http.Header{}
	header.Set("Origin", baseURL)

	// WebSocket bağlantısı
	conn, resp, err := dialer.Dial(u.String(), header)
	if err != nil {
		if resp != nil {
			body, _ := io.ReadAll(resp.Body)
			log.Printf("WebSocket response: %d - %s", resp.StatusCode, string(body))
		}
		return err
	}

	sc.conn = conn
	sc.sonPing = time.Now() // İlk ping zamanı
	log.Println("WebSocket bağlantısı kuruldu")

	// Event handler'ları kaydet
	sc.eventleriKaydet()

	// Mesaj okuma goroutine'i başlat
	go sc.mesajOku()

	return nil
}

// eventleriKaydet - Socket eventlerini kaydet
func (sc *SocketClient) eventleriKaydet() {
	// Bağlantı onay
	sc.On("FikoYT.ajan.baglan.onay", func(data interface{}) {
		log.Printf("Bağlantı onaylandı: %v", data)
	})

	// Mesaj eventi
	sc.On("FikoYT.ajan.mesaj", func(data interface{}) {
		if dataMap, ok := data.(map[string]interface{}); ok {
			log.Printf("Mesaj alındı: %v", dataMap)

			// Mesaj ID'sini al
			mesajId, _ := dataMap["mesajId"].(string)

			// ACK gönder - mesaj alındı
			if mesajId != "" {
				sc.mesajAckGonder(mesajId, "alindi")
			}

			// Mesajı işle ve gösterildiğinde ACK gönder
			sc.mesajHandler.MesajIsle(dataMap, func(mid string, cevap string) {
				// Mesaj gösterildi ACK
				if mid != "" {
					sc.mesajAckGonder(mid, "gosterildi")
				}
				// Kullanıcı cevabı varsa gönder
				if cevap != "" {
					sc.mesajCevabiGonder(mid, cevap)
				}
			})
		}
	})

	// Komut eventi (streaming destekli)
	sc.On("FikoYT.ajan.komut", func(data interface{}) {
		if dataMap, ok := data.(map[string]interface{}); ok {
			log.Printf("Komut alındı: %v", dataMap)

			// Streaming modunu kontrol et (varsayılan: true)
			streaming := true
			if s, ok := dataMap["streaming"].(bool); ok {
				streaming = s
			}

			if streaming {
				// Streaming mod - satır satır çıktı gönder
				go sc.komutHandler.KomutCalistirStreaming(dataMap,
					// Çıktı callback
					func(gorevId string, satir string, tip string) {
						sc.komutCiktiGonder(gorevId, satir, tip)
					},
					// Sonuç callback
					func(sonuc handlers.KomutSonuc) {
						sc.komutSonucGonder(sonuc)
					},
				)
			} else {
				// Klasik mod - tüm çıktıyı sonunda gönder
				go sc.komutHandler.KomutCalistir(dataMap, func(sonuc handlers.KomutSonuc) {
					sc.komutSonucGonder(sonuc)
				})
			}
		}
	})

	// Komut iptal eventi
	sc.On("FikoYT.ajan.komut.iptal", func(data interface{}) {
		if dataMap, ok := data.(map[string]interface{}); ok {
			gorevId, _ := dataMap["gorevId"].(string)
			if gorevId == "" {
				return
			}

			log.Printf("Komut iptal isteği: %s", gorevId)
			basarili := sc.komutHandler.KomutIptal(gorevId)

			// İptal onayı gönder
			sc.Emit("FikoYT.ajan.komut.iptal.onay", map[string]interface{}{
				"gorevId":  gorevId,
				"basarili": basarili,
				"zaman":    time.Now().Format(time.RFC3339),
			})
		}
	})

	// Program aç eventi
	sc.On("FikoYT.ajan.program.ac", func(data interface{}) {
		if dataMap, ok := data.(map[string]interface{}); ok {
			log.Printf("Program açılıyor: %v", dataMap)
			sc.komutHandler.ProgramAc(dataMap)
		}
	})

	// Sistem bilgisi isteme eventi
	sc.On("FikoYT.ajan.sistem.iste", func(data interface{}) {
		log.Printf("Sistem bilgisi istendi, gönderiliyor...")
		sistemBilgi, err := sc.sistemHandler.BilgiTopla()
		if err != nil {
			log.Printf("Sistem bilgisi toplama hatası: %v", err)
			return
		}
		// Tam sistem bilgisini gönder
		sc.Emit("FikoYT.ajan.sistem.cevap", map[string]interface{}{
			"ajanId":       sc.config.AjanId,
			"hostname":     sistemBilgi.Hostname,
			"os":           sistemBilgi.OS,
			"osVersiyon":   sistemBilgi.OsVersiyon,
			"platform":     sistemBilgi.Platform,
			"mimari":       sistemBilgi.Mimari,
			"cpuModel":     sistemBilgi.CPUModel,
			"cpuCekirdek":  sistemBilgi.CPUCekirdek,
			"cpuKullanim":  sistemBilgi.CPUKullanim,
			"ramToplam":    sistemBilgi.RAMToplam,
			"ramKullanan":  sistemBilgi.RAMKullanan,
			"ramYuzde":     sistemBilgi.RAMYuzde,
			"diskToplam":   sistemBilgi.DiskToplam,
			"diskYuzde":    sistemBilgi.DiskYuzde,
			"kullanici":    sistemBilgi.Kullanici,
			"uptime":       sistemBilgi.Uptime,
			"macAdresi":    sistemBilgi.MacAdresi,
			"ipAdresleri":  sistemBilgi.IpAdresleri,
			"ajanVersiyon": sistemBilgi.AjanVersiyon,
			"zaman":        time.Now().Format(time.RFC3339),
		})
		log.Printf("Sistem bilgisi gönderildi")
	})

	// ============== UZAK MASAÜSTÜ EVENTLERİ ==============

	// Genel remote event handler - tüm remote.* eventlerini işler
	remoteEvents := []string{
		// Screen events
		"FikoYT.ajan.remote.screen.capture",
		"FikoYT.ajan.remote.screen.stream.start",
		"FikoYT.ajan.remote.screen.stream.stop",
		"FikoYT.ajan.remote.screen.stream.config",
		"FikoYT.ajan.remote.screen.displays",
		// WebRTC events
		"FikoYT.ajan.remote.webrtc.start",
		"FikoYT.ajan.remote.webrtc.offer",
		"FikoYT.ajan.remote.webrtc.answer",
		"FikoYT.ajan.remote.webrtc.ice",
		"FikoYT.ajan.remote.webrtc.stop",
		"FikoYT.ajan.remote.webrtc.stats",
		// Input events
		"FikoYT.ajan.remote.input.mouse.move",
		"FikoYT.ajan.remote.input.mouse.click",
		"FikoYT.ajan.remote.input.mouse.down",
		"FikoYT.ajan.remote.input.mouse.up",
		"FikoYT.ajan.remote.input.mouse.scroll",
		"FikoYT.ajan.remote.input.key.press",
		"FikoYT.ajan.remote.input.key.down",
		"FikoYT.ajan.remote.input.key.up",
		"FikoYT.ajan.remote.input.type",
		"FikoYT.ajan.remote.input.combination",
		"FikoYT.ajan.remote.input.enable",
		"FikoYT.ajan.remote.input.disable",
		// File events
		"FikoYT.ajan.remote.file.list",
		"FikoYT.ajan.remote.file.drives",
		"FikoYT.ajan.remote.file.info",
		"FikoYT.ajan.remote.file.create",
		"FikoYT.ajan.remote.file.delete",
		"FikoYT.ajan.remote.file.rename",
		"FikoYT.ajan.remote.file.copy",
		"FikoYT.ajan.remote.file.move",
		"FikoYT.ajan.remote.file.read",
		"FikoYT.ajan.remote.file.write",
		"FikoYT.ajan.remote.file.search",
		"FikoYT.ajan.remote.file.compress",
		"FikoYT.ajan.remote.file.extract",
		"FikoYT.ajan.remote.file.download.start",
		"FikoYT.ajan.remote.file.download.chunk",
		"FikoYT.ajan.remote.file.upload.start",
		"FikoYT.ajan.remote.file.upload.chunk",
		// Process events
		"FikoYT.ajan.remote.process.list",
		"FikoYT.ajan.remote.process.info",
		"FikoYT.ajan.remote.process.kill",
		"FikoYT.ajan.remote.process.suspend",
		"FikoYT.ajan.remote.process.resume",
		"FikoYT.ajan.remote.process.tree",
		"FikoYT.ajan.remote.process.stats",
		"FikoYT.ajan.remote.process.start",
		// Plugin events
		"FikoYT.ajan.remote.plugin.list",
		"FikoYT.ajan.remote.plugin.load",
		"FikoYT.ajan.remote.plugin.unload",
		"FikoYT.ajan.remote.plugin.start",
		"FikoYT.ajan.remote.plugin.stop",
		"FikoYT.ajan.remote.plugin.stats",
		// Update events
		"FikoYT.ajan.remote.update.check",
		"FikoYT.ajan.remote.update.install",
		"FikoYT.ajan.remote.update.status",
		"FikoYT.ajan.remote.update.rollback",
	}

	for _, eventName := range remoteEvents {
		// Closure için kopyala
		event := eventName
		sc.On(event, func(data interface{}) {
			// Event adından action'ı çıkar (FikoYT.ajan.remote. prefix'ini kaldır)
			action := strings.TrimPrefix(event, "FikoYT.ajan.remote.")

			dataMap, ok := data.(map[string]interface{})
			if !ok {
				dataMap = make(map[string]interface{})
			}

			// İstek ID'si varsa al
			requestId, _ := dataMap["requestId"].(string)

			// Remote handler'a işlet
			result := sc.remoteHandler.ProcessEvent(action, dataMap)

			// Sonucu gönder
			result["ajanId"] = sc.config.AjanId
			result["action"] = action
			if requestId != "" {
				result["requestId"] = requestId
			}

			sc.Emit("FikoYT.ajan.remote.sonuc", result)
		})
	}

	// Remote handler'ı başlat
	sc.remoteHandler.Start()
}

// On - Event handler kaydet
func (sc *SocketClient) On(event string, handler func(data interface{})) {
	sc.mu.Lock()
	sc.eventHandlers[event] = handler
	sc.mu.Unlock()
}

// mesajOku - WebSocket mesajlarını oku
func (sc *SocketClient) mesajOku() {
	defer func() {
		sc.mu.Lock()
		manuelReconnect := sc.manuelYenidenBaglan
		sc.bagli = false
		sc.mu.Unlock()

		// durumCh'ye non-blocking gönder (kanal dolu olabilir)
		select {
		case sc.durumCh <- "Bağlantı Kesildi":
		default:
		}

		// Manuel reconnect varsa otomatik yeniden bağlama (race condition önleme)
		if manuelReconnect {
			log.Println("mesajOku: Manuel reconnect aktif, otomatik yeniden bağlama atlanıyor")
			return
		}

		// Otomatik yeniden bağlan
		go sc.otomatikYenidenBaglan()
	}()

	for {
		select {
		case <-sc.kapatCh:
			log.Println("mesajOku: kapatCh sinyali alındı, çıkılıyor")
			return
		default:
			// Read deadline ayarla (90 saniye - ping interval genelde 25-30 saniye)
			sc.mu.RLock()
			conn := sc.conn
			sc.mu.RUnlock()

			if conn == nil {
				log.Println("mesajOku: conn nil, çıkılıyor")
				return
			}

			conn.SetReadDeadline(time.Now().Add(90 * time.Second))
			_, message, err := conn.ReadMessage()
			if err != nil {
				log.Printf("Mesaj okuma hatası: %v", err)
				return
			}

			sc.handleEngineIOPacket(string(message))
		}
	}
}

// otomatikYenidenBaglan - Bağlantı kopunca otomatik yeniden bağlan
func (sc *SocketClient) otomatikYenidenBaglan() {
	// Manuel reconnect aktifse çık
	sc.mu.RLock()
	if sc.manuelYenidenBaglan {
		sc.mu.RUnlock()
		log.Println("Manuel reconnect aktif, otomatik yeniden bağlanma iptal")
		return
	}

	// kapatCh kontrol et (kapat() çağrıldıysa yeniden bağlama)
	select {
	case <-sc.kapatCh:
		sc.mu.RUnlock()
		log.Println("Bağlantı kapatıldı, yeniden bağlanma iptal")
		return
	default:
	}
	sc.mu.RUnlock()

	bekleme := 5 * time.Second
	maxBekleme := 60 * time.Second
	deneme := 0

	for {
		deneme++
		log.Printf("Yeniden bağlantı denemesi #%d (%v sonra)...", deneme, bekleme)
		time.Sleep(bekleme)

		// kapatCh tekrar kontrol et
		sc.mu.RLock()
		select {
		case <-sc.kapatCh:
			sc.mu.RUnlock()
			log.Println("Yeniden bağlantı iptal edildi")
			return
		default:
		}
		sc.mu.RUnlock()

		// Mevcut bağlantıyı temizle
		sc.mu.Lock()
		if sc.conn != nil {
			sc.conn.Close()
			sc.conn = nil
		}
		// Yeni kapatCh oluştur (channel yeniden kullanılamaz)
		sc.kapatCh = make(chan struct{})
		sc.mu.Unlock()

		err := sc.Baglan()
		if err == nil {
			log.Println("Yeniden bağlantı başarılı!")
			return
		}

		log.Printf("Yeniden bağlantı hatası: %v", err)

		// Exponential backoff
		bekleme = bekleme * 2
		if bekleme > maxBekleme {
			bekleme = maxBekleme
		}
	}
}

// handleEngineIOPacket - Engine.IO paketini işle
func (sc *SocketClient) handleEngineIOPacket(packet string) {
	if len(packet) == 0 {
		return
	}

	// Debug log - gelen paketi göster
	if len(packet) < 200 {
		log.Printf("Engine.IO paket alındı: %s", packet)
	} else {
		log.Printf("Engine.IO paket alındı: %s... (%d bytes)", packet[:50], len(packet))
	}

	packetType := packet[0]
	payload := ""
	if len(packet) > 1 {
		payload = packet[1:]
	}

	switch packetType {
	case engineOpen:
		// Engine.IO open paketi
		log.Printf("Engine.IO open: %s", payload)

		// Session bilgilerini parse et
		var openData EngineIOOpen
		if err := json.Unmarshal([]byte(payload), &openData); err == nil {
			sc.sid = openData.Sid
			log.Printf("Session ID: %s, PingInterval: %dms", openData.Sid, openData.PingInterval)
		}

		// Socket.IO CONNECT gönder - explicit default namespace ile
		// Format: 4 (Engine.IO message) + 0 (Socket.IO connect) + / (namespace) + , (separator)
		log.Println("Socket.IO CONNECT gönderiliyor (40/,)")
		if err := sc.sendRaw(string(engineMessage) + string(socketConnect) + "/,"); err != nil {
			log.Printf("HATA: Socket.IO CONNECT gönderilemedi: %v", err)
		}

	case enginePing:
		// Pong gönder
		log.Println("Ping alındı, pong gönderiliyor")
		sc.mu.Lock()
		sc.sonPing = time.Now()
		sc.mu.Unlock()
		sc.sendRaw(string(enginePong))

	case enginePong:
		// Pong alındı
		if payload == "probe" {
			log.Println("Probe pong alındı, upgrade gönderiliyor")
			sc.sendRaw("5")
		}

	case engineMessage:
		// Socket.IO paketi
		sc.handleSocketIOPacket(payload)

	case engineClose:
		log.Println("Engine.IO close alındı")
		sc.mu.Lock()
		sc.bagli = false
		sc.mu.Unlock()

	case '5': // Upgrade
		log.Println("Upgrade tamamlandı")
		sc.sendRaw(string(engineMessage) + string(socketConnect))
	}
}

// handleSocketIOPacket - Socket.IO paketini işle
func (sc *SocketClient) handleSocketIOPacket(packet string) {
	if len(packet) == 0 {
		return
	}

	packetType := packet[0]
	payload := ""
	if len(packet) > 1 {
		payload = packet[1:]
	}

	switch packetType {
	case socketConnect:
		// Bağlantı kuruldu
		log.Println("Socket.IO bağlantısı kuruldu")
		sc.mu.Lock()
		sc.bagli = true
		sc.mu.Unlock()
		sc.durumCh <- "Bağlı"

		// Ajan bağlantı bilgisi gönder
		sc.ajanBaglandiGonder()

		// Periyodik durum gönderimini başlat
		go sc.periyodikDurumGonder()

	case socketDisconnect:
		log.Println("Socket.IO disconnect alındı")
		sc.mu.Lock()
		sc.bagli = false
		sc.mu.Unlock()
		sc.durumCh <- "Bağlantı Kesildi"

	case socketEvent:
		// Event parse et: ["eventName", data]
		sc.handleEvent(payload)

	case socketAck:
		// ACK, şimdilik ignore

	case socketConnectError:
		log.Printf("Socket.IO connect error: %s", payload)
		sc.durumCh <- "Bağlantı Hatası"
	}
}

// handleEvent - Socket.IO eventini işle
func (sc *SocketClient) handleEvent(payload string) {
	var eventArray []interface{}
	if err := json.Unmarshal([]byte(payload), &eventArray); err != nil {
		log.Printf("Event parse hatası: %v", err)
		return
	}

	if len(eventArray) < 1 {
		return
	}

	eventName, ok := eventArray[0].(string)
	if !ok {
		return
	}

	var eventData interface{}
	if len(eventArray) > 1 {
		eventData = eventArray[1]
	}

	log.Printf("Event alındı: %s", eventName)

	// Handler'ı çağır
	sc.mu.RLock()
	handler, exists := sc.eventHandlers[eventName]
	sc.mu.RUnlock()

	if exists {
		handler(eventData)
	}
}

// Emit - Event gönder
func (sc *SocketClient) Emit(event string, data interface{}) error {
	// Bağlantı kontrolü
	sc.mu.RLock()
	bagli := sc.bagli
	conn := sc.conn
	sc.mu.RUnlock()

	if !bagli || conn == nil {
		return fmt.Errorf("bağlantı yok")
	}

	eventArray := []interface{}{event, data}
	payload, err := json.Marshal(eventArray)
	if err != nil {
		return err
	}

	// Socket.IO event: 42["eventName", data]
	packet := string(engineMessage) + string(socketEvent) + string(payload)
	return sc.sendRaw(packet)
}

// sendRaw - Ham mesaj gönder
func (sc *SocketClient) sendRaw(message string) (err error) {
	// Panic recovery - race condition'dan korunma
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("sendRaw panic: %v", r)
			log.Printf("sendRaw panic yakalandı: %v", r)
		}
	}()

	sc.writeMu.Lock()
	defer sc.writeMu.Unlock()

	// Double check with mutex held
	sc.mu.RLock()
	conn := sc.conn
	sc.mu.RUnlock()

	// Not: bagli kontrolü kaldırıldı çünkü Socket.IO CONNECT paketi
	// gönderilmeden önce bagli=false oluyor ve bu yüzden CONNECT hiç gönderilmiyordu!
	if conn == nil {
		return fmt.Errorf("bağlantı yok")
	}

	// Sadece kısa mesajları logla (frame data çok büyük)
	if len(message) < 500 {
		log.Printf(">>> WS GÖNDERİLİYOR: [%s] (len=%d)", message, len(message))
	} else {
		log.Printf(">>> WS GÖNDERİLİYOR: [%s...] (%d bytes)", message[:100], len(message))
	}
	return conn.WriteMessage(websocket.TextMessage, []byte(message))
}

// ajanBaglandiGonder - Ajan bağlantı bilgisi gönder
func (sc *SocketClient) ajanBaglandiGonder() {
	sistemBilgi, _ := sc.sistemHandler.BilgiTopla()

	data := map[string]interface{}{
		"ajanId": sc.config.AjanId,
		"ad":     sc.config.AjanAd,
		"sistem": sistemBilgi,
	}

	if err := sc.Emit("FikoYT.ajan.baglan", data); err != nil {
		log.Printf("Ajan bağlantı bilgisi gönderilemedi: %v", err)
		return
	}
	log.Printf("Ajan bağlantı bilgisi gönderildi: %s", sc.config.AjanId)
}

// mesajAckGonder - Mesaj teslim/görüntüleme onayı gönder
func (sc *SocketClient) mesajAckGonder(mesajId string, durum string) {
	data := map[string]interface{}{
		"mesajId": mesajId,
		"durum":   durum, // "alindi" veya "gosterildi"
		"zaman":   time.Now().Format(time.RFC3339),
	}
	if err := sc.Emit("FikoYT.ajan.mesaj.ack", data); err != nil {
		log.Printf("Mesaj ACK gönderilemedi: %v", err)
		return
	}
	log.Printf("Mesaj ACK gönderildi: %s -> %s", mesajId, durum)
}

// mesajCevabiGonder - Mesaj cevabı gönder
func (sc *SocketClient) mesajCevabiGonder(mesajId string, cevap string) {
	data := map[string]interface{}{
		"mesajId": mesajId,
		"cevap":   cevap,
	}
	if err := sc.Emit("FikoYT.ajan.mesaj.cevap", data); err != nil {
		log.Printf("Mesaj cevabı gönderilemedi: %v", err)
		return
	}
	log.Printf("Mesaj cevabı gönderildi: %s -> %s", mesajId, cevap)
}

// komutCiktiGonder - Komut çıktısı satır satır gönder (streaming)
func (sc *SocketClient) komutCiktiGonder(gorevId string, satir string, tip string) {
	data := map[string]interface{}{
		"gorevId": gorevId,
		"satir":   satir,
		"tip":     tip, // "stdout" veya "stderr"
		"zaman":   time.Now().Format(time.RFC3339),
	}
	if err := sc.Emit("FikoYT.ajan.komut.cikti", data); err != nil {
		log.Printf("Komut çıktısı gönderilemedi: %v", err)
	}
}

// komutSonucGonder - Komut sonucu gönder
func (sc *SocketClient) komutSonucGonder(sonuc handlers.KomutSonuc) {
	data := map[string]interface{}{
		"gorevId":     sonuc.GorevId,
		"cikti":       sonuc.Cikti,
		"hataCikti":   sonuc.HataCikti,
		"cikisDurumu": sonuc.CikisDurumu,
	}
	if err := sc.Emit("FikoYT.ajan.komut.sonuc", data); err != nil {
		log.Printf("Komut sonucu gönderilemedi: %v", err)
		return
	}
	log.Printf("Komut sonucu gönderildi: %s (durum: %d)", sonuc.GorevId, sonuc.CikisDurumu)
}

// periyodikDurumGonder - Periyodik durum raporu gönder
func (sc *SocketClient) periyodikDurumGonder() {
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			if sc.Bagli() {
				sistemBilgi := sc.sistemHandler.HizliBilgi()
				sc.Emit("FikoYT.ajan.durum", sistemBilgi)
			}
		case <-sc.kapatCh:
			return
		}
	}
}

// Bagli - Bağlantı durumu
func (sc *SocketClient) Bagli() bool {
	sc.mu.RLock()
	defer sc.mu.RUnlock()
	return sc.bagli
}

// Durum - Bağlantı durumu string
func (sc *SocketClient) Durum() string {
	if sc.Bagli() {
		return "Bağlı"
	}
	return "Bağlı Değil"
}

// YenidenBaglan - Yeniden bağlan
func (sc *SocketClient) YenidenBaglan() {
	log.Println("=== Manuel Yeniden Bağlantı Başlatılıyor ===")

	// 1. Manuel reconnect flag'ini ayarla (mesajOku'nun otomatik reconnect yapmasını engelle)
	sc.mu.Lock()
	sc.manuelYenidenBaglan = true
	sc.mu.Unlock()

	// 2. kapatCh'yi kapat (goroutine'leri durdur)
	sc.mu.Lock()
	select {
	case <-sc.kapatCh:
		// Zaten kapalı
	default:
		close(sc.kapatCh)
	}
	sc.mu.Unlock()

	// 3. Bağlantıyı kapat
	sc.mu.Lock()
	if sc.conn != nil {
		sc.conn.Close()
		sc.conn = nil
	}
	sc.bagli = false
	sc.mu.Unlock()

	// 4. Goroutine'lerin temizlenmesi için bekle
	time.Sleep(500 * time.Millisecond)

	// 5. Yeni kapatCh oluştur
	sc.mu.Lock()
	sc.kapatCh = make(chan struct{})
	sc.manuelYenidenBaglan = false // Flag'i sıfırla
	sc.mu.Unlock()

	// 6. Yeniden bağlan
	log.Println("Yeniden bağlantı deneniyor...")
	err := sc.Baglan()
	if err != nil {
		log.Printf("Manuel yeniden bağlantı hatası: %v", err)
		// Başarısız olursa otomatik yeniden bağlantı mekanizmasını tetikle
		go sc.otomatikYenidenBaglan()
	} else {
		log.Println("=== Manuel Yeniden Bağlantı Başarılı ===")
	}
}

// Kapat - Bağlantı kapat
func (sc *SocketClient) Kapat() {
	sc.mu.Lock()
	defer sc.mu.Unlock()

	// Remote handler'ı durdur
	if sc.remoteHandler != nil {
		sc.remoteHandler.Stop()
	}

	// Kanal zaten kapalı mı kontrol et
	select {
	case <-sc.kapatCh:
		// Zaten kapalı
	default:
		close(sc.kapatCh)
	}

	if sc.conn != nil {
		sc.conn.Close()
		sc.conn = nil
	}
	sc.bagli = false
}

// DurumKanali - Durum değişikliği kanalı
func (sc *SocketClient) DurumKanali() <-chan string {
	return sc.durumCh
}
