package FikoYTKullanici

import (
	"context"
	"log"
	FikoYTMap "server/sistem/fikoyt_map"
	fiko_mongo "server/sistem/fikoyt_mongo"
	"server/sistem/fikoyt_ortak"

	"github.com/gofiber/fiber/v3"
	"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"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type FikoYTKullanici struct {
	Id      interface{}
	Isim    interface{}
	SoyIsim interface{}
}

func Yeni(c fiber.Ctx, objectIDStr string) *FikoYTKullanici {

	if objectIDStr == "" {
		return nil
	}

	objectID, err := primitive.ObjectIDFromHex(objectIDStr)
	if err != nil {
		return nil
	}

	dbClient := fiko_mongo.GetMongoDBClient() // MongoDB bağlantısını döndüren varsayımsal bir fonksiyon.

	goUyeler := dbClient.Database("fikoyt").Collection("goUyeler")

	var kytUye FikoYTMap.FikoYTMap
	err = goUyeler.FindOne(
		context.TODO(),
		fiber.Map{"_id": objectID},
		&options.FindOneOptions{
			Projection: fiber.Map{
				"parola":         0,
				"epostaOnayKodu": 0,
				"anlasma":        0,
				"aktifDurum":     0,
			},
		},
	).Decode(&kytUye)

	if err != nil {
		return nil
	}

	// fmt.Println(kytUye)
	return &FikoYTKullanici{
		Id:      objectIDStr,
		Isim:    kytUye["isim"],
		SoyIsim: kytUye["soyIsim"],
	}
}

/***/

func YeniSoketten(socketId string) *FikoYTKullanici {
	if socketId == "" {
		return nil
	}

	ctx := context.TODO()

	var results []bson.M

	pipeline := mongo.Pipeline{
		{{Key: "$match", Value: bson.M{"soket": socketId}}},
		// {
		// 	{Key: "$lookup", Value: bson.M{
		// 		"from":         "goCihazlar",
		// 		"localField":   "cihaz",
		// 		"foreignField": "kimlik",
		// 		"as":           "cihaz",
		// 	}},
		// },
		// {
		// 	{Key: "$unwind", Value: bson.M{
		// 		"path":                       "$cihaz",
		// 		"preserveNullAndEmptyArrays": true,
		// 	}},
		// },
	}

	cursor, err := fiko_mongo.GetMongoDBClient().
		Database("fikoyt").
		Collection("goSoketler").
		Aggregate(ctx, pipeline, &options.AggregateOptions{})

	if err != nil {
		log.Fatal(err)
	}

	if err := cursor.All(ctx, &results); err != nil {
		log.Fatal(err)
	}

	if len(results) == 0 {
		return nil
	}

	if results[0]["kullanici"] == nil {
		return nil
	}

	kullanici_id := results[0]["kullanici"].(primitive.ObjectID)

	objectIDStr := kullanici_id.Hex()

	defer cursor.Close(ctx)
	/**/

	if objectIDStr == "" {
		return nil
	}

	objectID, err := primitive.ObjectIDFromHex(objectIDStr)
	if err != nil {
		return nil
	}

	dbClient := fiko_mongo.GetMongoDBClient() // MongoDB bağlantısını döndüren varsayımsal bir fonksiyon.

	goUyeler := dbClient.Database("fikoyt").Collection("goUyeler")

	var kytUye FikoYTMap.FikoYTMap
	err = goUyeler.FindOne(
		context.TODO(),
		fiber.Map{"_id": objectID},
		&options.FindOneOptions{
			Projection: fiber.Map{
				"parola":         0,
				"epostaOnayKodu": 0,
				"anlasma":        0,
				"aktifDurum":     0,
			},
		},
	).Decode(&kytUye)

	if err != nil {
		return nil
	}

	// fmt.Println(kytUye)
	return &FikoYTKullanici{
		Id:      objectIDStr,
		Isim:    kytUye["isim"],
		SoyIsim: kytUye["soyIsim"],
	}
}

/***/

func (f FikoYTKullanici) IsleObjectId() FikoYTKullanici {

	// Check if the value is a string and if it's a valid ObjectId format
	if strVal, ok := f.Id.(string); ok {
		if len(strVal) == 24 { // MongoDB ObjectId is 24 characters long
			if objectId, err := primitive.ObjectIDFromHex(strVal); err == nil {
				// If it's a valid ObjectId, replace the value with ObjectId
				f.Id = objectId
			}
		}

	}
	return f
}

func (f FikoYTKullanici) AktifCihazlar() bson.M {
	ctx := context.TODO()

	var results []bson.M

	pipeline := mongo.Pipeline{
		{{Key: "$match", Value: bson.M{"kullanici": f.IsleObjectId().Id.(primitive.ObjectID)}}},
		{
			{Key: "$lookup", Value: bson.M{
				"from":         "goCihazlar",
				"localField":   "cihaz",
				"foreignField": "kimlik",
				"as":           "cihaz",
			}},
		},
		{
			{Key: "$unwind", Value: bson.M{
				"path":                       "$cihaz",
				"preserveNullAndEmptyArrays": true,
			}},
		},
		{{Key: "$group", Value: bson.D{
			{Key: "_id", Value: "$cihaz.tipi"},
			{Key: "adet", Value: bson.D{{Key: "$sum", Value: 1}}},
		}}},
		{{Key: "$group", Value: bson.D{
			{Key: "_id", Value: nil},
			{Key: "sonuclar", Value: bson.D{
				{Key: "$push", Value: bson.D{
					{Key: "k", Value: "$_id"},
					{Key: "v", Value: "$adet"},
				}},
			}},
		}}},
		{{Key: "$replaceRoot", Value: bson.D{
			{Key: "newRoot", Value: bson.D{
				{Key: "$arrayToObject", Value: "$sonuclar"},
			}},
		}}},
	}

	cursor, err := fiko_mongo.GetMongoDBClient().
		Database("fikoyt").
		Collection("goSoketler").
		Aggregate(ctx, pipeline, &options.AggregateOptions{})

	if err != nil {
		log.Fatal(err)
	}

	if err := cursor.All(ctx, &results); err != nil {
		log.Fatal(err)
	}

	// Varsayılanlar
	defaults := bson.M{
		"desktop": 0,
		"machine": 0,
		"mobile":  0,
		"tablet":  0,
		"tv":      0,
	}

	// DB'den gelen sonuç (örnek)

	// Sonucu defaults ile birleştiriyoruz
	for _, item := range results {
		for k, v := range item {
			defaults[k] = v
		}
	}

	if len(results) == 0 {
		results = []bson.M{{"desktop": 0, "mobile": 0, "tablet": 0, "tv": 0, "machine": 0}} // Tek boş map
	}

	defer cursor.Close(ctx)

	return []bson.M{defaults}[0]
}

/**/
func (f FikoYTKullanici) OlayYolla(olay string, data ...any) {
	// ctx := context.TODO()

	soketler := f.Soketler()

	for _, soket := range soketler {
		soket.Emit(olay, data)
	}
}

/**/
func (f FikoYTKullanici) Soketler() []socket.RemoteSocket {
	ctx := context.TODO()

	var results []socket.RemoteSocket = []socket.RemoteSocket{}

	pipeline := mongo.Pipeline{
		{{Key: "$match", Value: bson.M{"kullanici": f.IsleObjectId().Id.(primitive.ObjectID)}}},
	}

	cursor, err := fiko_mongo.GetMongoDBClient().
		Database("fikoyt").
		Collection("goSoketler").
		Aggregate(ctx, pipeline, &options.AggregateOptions{})

	if err != nil {
		log.Fatal(err)
	}

	// Sonuçları dolaş
	for cursor.Next(ctx) {
		var result bson.M
		if err := cursor.Decode(&result); err != nil {
			// log.Printf("Sonuç çözümleme hatası: %v\n", err)
			continue
		}

		socketId, ok := result["soket"].(string)
		if !ok {
			// log.Println("socketId uygun formatta değil.")
			continue
		}

		// Tüm socketleri getir (örneğin bir cache ya da bağlı soket havuzundan)
		// allSockets, _ := fiko_socket_io.FikoSocketIo.Sockets().AllSockets() // Bu, mevcut tüm socket'leri döndüren varsayımsal bir fonksiyondur.
		fikoyt_ortak.FikoSocketIo.FetchSockets()(func(sockets []*socket.RemoteSocket, _ error) {
			for _, v := range sockets {
				if v.Id() == socket.SocketId(socketId) {
					results = append(results, *v)
					// if cb != nil {
					// 	cb(v)
					// }
				}
			}
		})

	}

	if err := cursor.Err(); err != nil {
		log.Printf("Cursor hatası: %v\n", err)
	}

	return results
}
