package fiko_socket_io

import (
	"context"
	"fmt"
	"log"
	"reflect"

	fiko_mongo "server/sistem/fikoyt_mongo"
	fikoyt_ortak "server/sistem/fikoyt_ortak"
	"time"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/middleware/adaptor"
	EIOLog "github.com/zishang520/engine.io/v2/log"
	"github.com/zishang520/engine.io/v2/types"
	"github.com/zishang520/socket.io/v2/socket"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var FikoSocketIo *socket.Server

func Ayarla(app *fiber.App) {
	baglantilariSil()
	EIOLog.DEBUG = true
	socketioSettings := socket.DefaultServerOptions()
	socketioSettings.SetServeClient(true)
	// c.SetConnectionStateRecovery(&socket.ConnectionStateRecovery{})
	socketioSettings.SetAllowEIO3(true)
	socketioSettings.SetAllowUpgrades(true)
	socketioSettings.SetTransports(types.NewSet("polling", "websocket", "webtransport"))

	socketioSettings.SetPingInterval(2000 * time.Millisecond)
	socketioSettings.SetPingTimeout(2000 * time.Millisecond)
	socketioSettings.SetMaxHttpBufferSize(1000000)
	socketioSettings.SetConnectTimeout(3000 * time.Millisecond)
	socketioSettings.SetCors(&types.Cors{
		Origin:      "*",
		Credentials: true,
	})
	FikoSocketIo = socket.NewServer(nil, nil)

	FikoSocketIo.On("connection", func(clients ...interface{}) {
		client := clients[0].(*socket.Socket)

		// fmt.Println(clients...)

		ClientBaglandi(client)
	})

	//
	app.Get("/socket.io/", adaptor.HTTPHandler(FikoSocketIo.ServeHandler(socketioSettings)))
	app.Post("/socket.io/", adaptor.HTTPHandler(FikoSocketIo.ServeHandler(socketioSettings)))

	// FikoSocketIo.Use(func(socket *socket.Socket, next func(*socket.ExtendedError)) {
	// 	fmt.Println(socket.Request().Headers())
	// 	next(nil)
	// })
	// FikoSocketIo.FetchSockets()
}

// hasKey kontrol fonksiyonu
func hasKey(data interface{}, key string) bool {
	if reflect.TypeOf(data).Kind() == reflect.Map {
		return reflect.ValueOf(data).MapIndex(reflect.ValueOf(key)).IsValid()
	}
	return false
}

func ClientBaglandi(client *socket.Socket) {
	client.On("disconnect", func(args ...interface{}) {
		ctx := context.TODO()
		collectionGoSoketler := fiko_mongo.GetMongoDBClient().Database("fikoyt").Collection("goSoketler")

		soketSorgu := bson.M{
			"soket": string(client.Id()),
		}

		_, err := collectionGoSoketler.DeleteMany(ctx, soketSorgu)
		if err != nil {
			log.Printf("Soket silme hatası: %v", err)
		}

		var k = fikoyt_ortak.YeniSoketten(string(client.Id()))

		k.OlayYolla("FikoYT.sistem.cihaz.bağlandı.toplamlar", k.AktifCihazlar())
	})
	/**/
	client.On("FikoYT.sistem.io.cihaz.baglandi", func(args ...interface{}) {
		// log.Println("FikoYT.sistem.io.cihaz.baglandi", args[len(args)-2])
		soketBaglandi(string(client.Id()), args[len(args)-2].(map[string]interface{}))
	})
	/**/
	// client.On("FikoYT.sistem.io.cihaz.guncelle", func(args ...interface{}) {
	// 	log.Println("FikoYT.sistem.io.cihaz.guncelle", args[len(args)-2])
	// 	soketBaglandi(string(client.Id()), args[len(args)-2].(map[string]interface{}))
	// })
}

/**/
func baglantilariSil() {
	collectionBaglantilar := fiko_mongo.GetMongoDBClient().Database("fikoyt").Collection("hareketler")

	// İlk sorgu: "FikoYT.sistem.io.cihaz.baglantilar" verisini sil
	// sorgu := bson.M{
	// 	"vt": "FikoYT.sistem.io.cihaz.baglantilar",
	// }

	// _, err := collectionBaglantilar.DeleteMany(context.TODO(), sorgu)
	// if err != nil {
	// 	log.Fatalf("DeleteMany error: %v", err)
	// 	return
	// }

	// İkinci sorgu: "FikoYT.sistem.io.cihazlar.cihaz" verisini güncelle
	sorgu := bson.M{
		"vt": "FikoYT.sistem.io.cihazlar.cihaz",
	}

	// UpdateMany işlemi, info.sockets'ı boş bir dizi olarak ayarlar
	update := bson.M{
		"$set": bson.M{
			"veri.soketler": []interface{}{},
		},
	}

	collectionBaglantilar.UpdateMany(context.TODO(), sorgu, update, options.Update().SetUpsert(false))

	collectionGoSoketler := fiko_mongo.GetMongoDBClient().Database("fikoyt").Collection("goSoketler")

	collectionGoSoketler.DeleteMany(context.TODO(), bson.M{})
}

/**/
func soketBaglandi(clientID string, receivedData map[string]interface{}) {
	// MongoDB bağlamı ve koleksiyonu
	ctx := context.TODO()
	dbClient := fiko_mongo.GetMongoDBClient() // MongoDB bağlantısını döndüren varsayımsal bir fonksiyon.
	// collectionHareketler := dbClient.Database("fikoyt").Collection("hareketler")
	/** NOT:  Yeni Bağlantı kaydı */
	collectionGoCihazlar := dbClient.Database("fikoyt").Collection("goCihazlar")

	cihazMap, ok := receivedData["FikoYT"].(map[string]interface{})
	if !ok {
		log.Println("Hata: receivedData['FikoYT'] beklenen formatta değil.")
		return
	}

	cihazKimlikStr, ok := cihazMap["cihaz_kimlik"].(string)
	if !ok {
		log.Println("Hata: cihaz_kimlik string değil.")
		return
	}

	cihazKimlik, err := primitive.ObjectIDFromHex(cihazKimlikStr)
	if err != nil {
		log.Printf("Hata: Geçersiz ObjectID (%v): %v\n", cihazKimlikStr, err)
		return
	}

	cihazSorgu := bson.M{
		"kimlik": cihazKimlik,
	}

	cihazKayit := bson.M{
		"tarih":    time.Now(),
		"kimlik":   cihazKimlik,
		"tipi":     cihazMap["cihaz_tipi"],
		"bilgiler": cihazMap["cihaz_bilgi"],
		// "soket": clientID, // eğer gerekiyorsa aktif hale getir
	}

	_, erSr := collectionGoCihazlar.UpdateMany(ctx, cihazSorgu, bson.M{
		"$set": cihazKayit,
	}, options.Update().SetUpsert(true))
	if erSr != nil {
		log.Printf(" error: %v\n", erSr)
		// return
	}

	/** NOT:  Soketler */
	collectionGoSoketler := dbClient.Database("fikoyt").Collection("goSoketler")
	soketSorgu := bson.M{
		"soket": clientID,
		"cihaz": cihazKimlik,
	}

	soketKayit := bson.M{
		"tarih": time.Now(),
		"soket": clientID,
		"cihaz": cihazKimlik,
		// "soket": clientID, // eğer gerekiyorsa aktif hale getir
	}
	/***/
	kullaniciKimlikStr, ok := receivedData["FikoYT"].(map[string]interface{})["kullanici_kimlik"].(string)
	if !ok {
		// log.Println("Hata: Kullanıcı kimlik bilgisi alınamadı")
		// return
	}

	kullaniciKimlik, err := primitive.ObjectIDFromHex(kullaniciKimlikStr)
	if err != nil {
		// log.Printf("Hata: Geçersiz Kullanıcı ObjectID (%v): %v\n", kullaniciKimlikStr, err)
		// return
	} else {
		soketKayit["kullanici"] = kullaniciKimlik
	}

	/***/
	_, erS := collectionGoSoketler.UpdateMany(ctx, soketSorgu, bson.M{
		"$set": soketKayit,
	}, options.Update().SetUpsert(true))
	if erS != nil {
		log.Printf("error: %v\n", erS)
		// return
	}

	var k = fikoyt_ortak.YeniSoketten(clientID)
	fmt.Println(k.AktifCihazlar().(string))

	k.OlayYolla("FikoYT.sistem.cihaz.bağlandı.toplamlar", k.AktifCihazlar())

}

/**/
