package fiko_mongo

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/middleware/session"
	"github.com/gofiber/storage/mongodb"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var Client *mongo.Client
var Session *session.Store
var MongoStore *mongodb.Storage
var SessionConfig session.Config
var DBName string

func Init(app *fiber.App) {
	databaseURL := os.Getenv("mongo_uri")
	DBName = os.Getenv("mongo_db")
	if DBName == "" {
		DBName = "fikoyt_finans"
	}

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	client, err := mongo.Connect(ctx, options.Client().ApplyURI(databaseURL))
	if err != nil {
		log.Fatal("MongoDB baglanti hatasi:", err)
	}

	if err := client.Ping(ctx, nil); err != nil {
		log.Fatal("MongoDB ping hatasi:", err)
	}

	Client = client
	log.Printf("MongoDB baglanildi: %s", DBName)

	setMiddleWare(app)
	setSessionMotor(app)

	ensureIndexes()
}

func GetMongoDBClient() *mongo.Client {
	return Client
}

func GetSession() *session.Store {
	return Session
}

func GetDB() *mongo.Database {
	return Client.Database(DBName)
}

func GetCollection(name string) *mongo.Collection {
	return Client.Database(DBName).Collection(name)
}

func GetFinansCollection() *mongo.Collection {
	kolIsmi := os.Getenv("finans_koleksiyon")
	if kolIsmi == "" {
		kolIsmi = "finans"
	}
	return Client.Database(DBName).Collection(kolIsmi)
}

func setSessionMotor(_ *fiber.App) {
	MongoStore = mongodb.New(mongodb.Config{
		ConnectionURI: os.Getenv("mongo_uri"),
		Database:      DBName,
		Collection:    "go_sessions",
		Reset:         false,
	})

	SessionConfig = session.Config{
		Storage:        MongoStore,
		CookieSecure:   false,
		CookieHTTPOnly: true,
		CookieSameSite: "lax",
		Expiration:     24 * time.Hour,
		KeyLookup:      "cookie:ffsid",
	}
	Session = session.New(SessionConfig)
	Session.RegisterType(bson.M{})
}

func setMiddleWare(app *fiber.App) {
	app.Use(func(c fiber.Ctx) error {
		ses, _ := GetSession().Get(c)
		c.Locals("session", ses)
		return c.Next()
	})
}

func ensureIndexes() {
	ctx := context.TODO()
	kol := GetFinansCollection()

	indexes := []mongo.IndexModel{
		{Keys: bson.D{{Key: "tur", Value: 1}}},
		{Keys: bson.D{{Key: "sistemId", Value: 1}}},
		{Keys: bson.D{{Key: "sahipId", Value: 1}}},
		{Keys: bson.D{{Key: "tur", Value: 1}, {Key: "sistemId", Value: 1}}},
		{Keys: bson.D{{Key: "sistemId", Value: 1}, {Key: "sahipId", Value: 1}}},
		{Keys: bson.D{{Key: "_guncellemeTarihi", Value: 1}}},
		{Keys: bson.D{{Key: "_silindi", Value: 1}}},
		{Keys: bson.D{{Key: "tur", Value: 1}, {Key: "sistemId", Value: 1}, {Key: "_silindi", Value: 1}}},
		{Keys: bson.D{{Key: "veri.id", Value: 1}, {Key: "sistemId", Value: 1}}},
	}

	_, err := kol.Indexes().CreateMany(ctx, indexes)
	if err != nil {
		log.Printf("Index olusturma uyarisi: %v", err)
	} else {
		log.Println("MongoDB indexleri hazir")
	}

	kulKol := GetCollection("kullanicilar")
	kulIndexes := []mongo.IndexModel{
		{Keys: bson.D{{Key: "kullaniciAdi", Value: 1}}, Options: options.Index().SetUnique(true)},
		{Keys: bson.D{{Key: "eposta", Value: 1}}, Options: options.Index().SetUnique(true)},
	}
	_, _ = kulKol.Indexes().CreateMany(ctx, kulIndexes)
}

func SetSessionData(s *session.Session, key string, value interface{}) error {
	data, err := json.Marshal(value)
	if err != nil {
		return fmt.Errorf("marshal hatasi: %v", err)
	}
	s.Set(key, data)
	if err := s.Save(); err != nil {
		return fmt.Errorf("session kaydetme hatasi: %v", err)
	}
	return nil
}

func GetSessionData(s *session.Session, key string) (interface{}, error) {
	value := s.Get(key)
	if value == nil {
		return nil, fmt.Errorf("anahtar bulunamadi: %s", key)
	}
	data, ok := value.([]byte)
	if !ok {
		return nil, fmt.Errorf("beklenen []byte, gelen %T", value)
	}
	var result interface{}
	if err := json.Unmarshal(data, &result); err != nil {
		return nil, fmt.Errorf("unmarshal hatasi: %v", err)
	}
	return result, nil
}
