package kokDB

import (
	"context"
	"fmt"
	FikoYTCtx "server/sistem/fikoyt_ctx"
	FikoYTMap "server/sistem/fikoyt_map"

	"github.com/gofiber/fiber/v3"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func convertStagesToPipeline(stages []interface{}) (mongo.Pipeline, error) {
	var pipeline mongo.Pipeline
	for _, stage := range stages {
		var doc map[string]interface{}

		switch s := stage.(type) {
		case map[string]interface{}:
			doc = s
		case FikoYTMap.FikoYTMap:
			doc = map[string]interface{}(s) // Tip dönüşümü
		default:
			return nil, fmt.Errorf("stage tipi map[string]interface{} değil, %T", stage)
		}

		bsonDoc := bson.D{}
		for k, v := range doc {
			bsonDoc = append(bsonDoc, bson.E{Key: k, Value: v})
		}
		pipeline = append(pipeline, bsonDoc)
	}
	return pipeline, nil
}

func fikoyt_sistem_db_agregate(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)
	db := c.Params("db")

	koleksiyon := FikoYT.Koleksiyon(db)
	// var dbMap FikoYTMap.FikoYTMap
	ctx := context.TODO()

	var results []bson.M

	FikoYT.Istek.Json.IsleObjectId()

	aggrRaw, ok := FikoYT.Istek.Json["aggregate"]
	if !ok {
		return c.Status(200).JSON(FikoYTMap.FikoYTMap{})
	}

	aggrSlice, ok := aggrRaw.([]interface{})
	if !ok {
		return c.Status(200).JSON(FikoYTMap.FikoYTMap{})
	}

	pipeline, err := convertStagesToPipeline(aggrSlice)
	if err != nil {
		fmt.Println("Pipeline dönüşüm hatası:", err)
		return c.Status(200).JSON(FikoYTMap.FikoYTMap{})
	}

	cursor, err := koleksiyon.Aggregate(ctx, pipeline, &options.AggregateOptions{})
	// Varsayılanlar
	if err != nil {

		return nil
	}

	defer cursor.Close(ctx)

	cursor.All(ctx, &results)

	// prettyJson, _ := json.MarshalIndent(pipeline, "", "  ")
	// fmt.Println("Pipeline JSON:", string(prettyJson))

	// DB'den gelen sonuç (örnek)
	FikoYT.Cevap.Sonuc = results

	return c.JSON(results)
}

func fikoyt_sistem_db_ekle(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)
	db := c.Params("db")

	koleksiyon := FikoYT.Koleksiyon(db)

	// var dbMap FikoYTMap.FikoYTMap
	// ctx := context.TODO()

	FikoYT.Istek.Json.IsleObjectId()
	// koleksiyon.CountDocuments(context.TODO(), FikoYTMap.FikoYTMap{})
	//------------------------------------->

	var sonuclar interface{} = nil
	var err interface{} = nil

	switch FikoYT.Istek.JsonTip {
	case "Object":
		sonuclar, err = FikoYT.EkleYadaGuncelle(koleksiyon, FikoYT.Istek.Json)
		if err != nil {
			fmt.Println(err)
			sonuclar = err
		}
	case "Array":
		sonuclar, err = FikoYT.EkleYadaGuncelle(koleksiyon, FikoYT.Istek.JsonArray)
		if err != nil {
			fmt.Println(err)
			sonuclar = err
		}
	default:

	}
	// rslt, err := koleksiyon.InsertOne(ctx, FikoYT.Istek.Json)

	//------------------------------------->
	if len(FikoYT.Istek.Dosyalar) > 0 {
		dosya := FikoYT.Istek.Dosyalar[0]
		dosya.Kaydet()
		dosya.Isle()
		dosya.KaydetGridFs(fiber.Map{"yol": "./hareketler/" + db, "kid": FikoYT.AktifKullanici.Id})

		dosya.TemizleDosyalar()

	}

	// DB'den gelen sonuç (örnek)
	FikoYT.Cevap.Sonuc = sonuclar

	return c.JSON(sonuclar)
}

func fikoyt_sistem_db_sil(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)
	db := c.Params("db")

	koleksiyon := FikoYT.Koleksiyon(db)
	ctx := context.TODO()

	// Gelen filtreleri işle
	FikoYT.Istek.Json.IsleObjectId()

	// Silme işlemi sonucu
	var sonuc *mongo.DeleteResult
	var err error

	switch FikoYT.Istek.JsonTip {
	case "Object":
		sonuc, err = koleksiyon.DeleteMany(ctx, FikoYT.Istek.Json)
	case "Array":
		// Array ile gelen filtrelerin her biri için silme işlemi yapılır
		var toplamSilinen int64 = 0
		for _, filtre := range FikoYT.Istek.JsonArray {
			if m, ok := filtre.(FikoYTMap.FikoYTMap); ok {
				m.IsleObjectId()
				if r, e := koleksiyon.DeleteMany(ctx, m); e == nil {
					toplamSilinen += r.DeletedCount
				}
			}
		}
		// Custom response için sahte DeleteResult döndürüyoruz
		sonuc = &mongo.DeleteResult{DeletedCount: toplamSilinen}
	default:
		return c.Status(400).JSON(fiber.Map{"hata": "Geçersiz JsonTip"})
	}

	if err != nil {
		fmt.Println("Silme hatası:", err)
		return c.Status(500).JSON(false)
	}

	FikoYT.Cevap.Sonuc = sonuc
	return c.JSON(true)
}

func fikoyt_sistem_db_guncelle(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)
	db := c.Params("db")
	koleksiyon := FikoYT.Koleksiyon(db)
	ctx := context.TODO()

	// Gelen JSON'u işle (ObjectId dönüştür vs.)
	FikoYT.Istek.Json.IsleObjectId()

	// 1. Filter
	filterRaw, ok := FikoYT.Istek.Json["filter"]
	if !ok {
		return c.Status(400).JSON(fiber.Map{"hata": "filter alanı zorunludur"})
	}
	filter, ok := filterRaw.(map[string]interface{})
	if !ok {
		return c.Status(400).JSON(fiber.Map{"hata": "filter tipi hatalı"})
	}
	filterMap := FikoYTMap.FikoYTMap(filter)
	filterMap.IsleObjectId()

	// 2. Update verileri (örnek: "set", "data", "veri", vs.)
	updateRaw, ok := FikoYT.Istek.Json["veri"]
	if !ok {
		updateRaw, ok = FikoYT.Istek.Json["set"]
	}
	if !ok {
		updateRaw, ok = FikoYT.Istek.Json["data"]
	}
	if !ok {
		return c.Status(400).JSON(fiber.Map{"hata": "güncellenecek veri (veri / set / data) eksik"})
	}
	updateData, ok := updateRaw.(map[string]interface{})
	if !ok {
		return c.Status(400).JSON(fiber.Map{"hata": "güncellenecek veri tipi hatalı"})
	}
	updateMap := FikoYTMap.FikoYTMap(updateData)
	updateMap.IsleObjectId()

	// 3. UpdateMany mi UpdateOne mı?
	multi := false
	if m, ok := FikoYT.Istek.Json["multi"].(bool); ok {
		multi = m
	}

	var result *mongo.UpdateResult
	var err error

	if multi {
		result, err = koleksiyon.UpdateMany(ctx, filterMap, bson.M{"$set": updateMap})
	} else {
		result, err = koleksiyon.UpdateOne(ctx, filterMap, bson.M{"$set": updateMap})
	}

	if err != nil {
		fmt.Println("Güncelleme hatası:", err)
		return c.Status(500).JSON(fiber.Map{"hata": err.Error()})
	}

	FikoYT.Cevap.Sonuc = result
	return c.JSON(result)
}
