package fiko_mongo

import (
	"context"
	"encoding/json"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	"image/png"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/disintegration/imaging"
	"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/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/gridfs"
	"go.mongodb.org/mongo-driver/mongo/options"
	"github.com/chai2010/webp"
)

var Client *mongo.Client
var Session *session.Store
var MongoStore *mongodb.Storage
var SessionConfig session.Config

func Init(app *fiber.App) {
	// MongoDB bağlantı URL'si
	databaseURL := "mongodb://127.0.0.1:8001/"
	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)

	// MongoDB bağlantısını kuruyoruz
	client, err := mongo.Connect(ctx, options.Client().ApplyURI(databaseURL))
	if err != nil {
		log.Fatal(err)
	}

	// Bağlantıyı global Client değişkenine atıyoruz
	Client = client
	setMiddleWare(app)
	setSessionMotor(app)
	setRoutes(app)

}

// GetMongoDBClient fonksiyonu mevcut MongoDB bağlantısını döndürür
func GetMongoDBClient() *mongo.Client {
	return Client
}

func GetSession() *session.Store {
	return Session
}

func setSessionMotor(_ *fiber.App) { // Session middleware
	// MongoDB'yi storage olarak ayarlıyoruz
	MongoStore = mongodb.New(mongodb.Config{
		Host:       "127.0.0.1",
		Port:       8001,
		Database:   "fikoyt",
		Collection: "go_sessions",
		Reset:      false,
	})

	// Session middleware yapılandırması
	SessionConfig = session.Config{
		Storage: MongoStore, CookieSecure: true, CookieHTTPOnly: true, CookieSameSite: "lax", Expiration: 24 * time.Hour, KeyLookup: "cookie:sid",
	}
	Session = session.New(SessionConfig)
	Session.RegisterType(bson.M{})
}

func setRoutes(app *fiber.App) {
	app.Get("/fikomongo", func(c fiber.Ctx) error {
		// ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
		// // MongoDB koleksiyonundan veri almak
		// collection := GetMongoDBClient().Database("fikoyt").Collection("hareketler")

		// // Find sorgusuna limit ve skip parametrelerini ekleyerek verileri alıyoruz
		// findOptions := options.Find()
		// findOptions.SetLimit(2)
		// findOptions.SetSkip(0)

		// cursor, err := collection.Find(ctx, bson.D{}, findOptions)
		// if err != nil {
		// 	log.Fatal(err)
		// }
		// defer cursor.Close(ctx)

		// // Verileri tutacak bir dilim
		// var results []bson.M
		// cursor.All(ctx, &results)

		// Eğer cursor'dan çıkarken hata varsa
		// if err := cursor.Err(); err != nil {
		// 	log.Fatal(err)
		// }
		session := c.Locals("session").(*session.Session)

		SetSessionData(session, "test", bson.M{"Test": "Deneme"})
		// Session verisini JSON olarak döndürüyoruz
		return c.Status(200).JSON(true)
	})
	
app.Get("/fikoyt.com.FikoYT.sistem.aktifKullanici.hareketler.:id.resim", func(c fiber.Ctx) error {
    objectIDStr := c.Params("id")

    if objectIDStr == "" {
        return c.Status(fiber.StatusBadRequest).SendString("ObjectId parametresi gerekli")
    }

    objectID, err := primitive.ObjectIDFromHex(objectIDStr)
    if err != nil {
        return c.Status(fiber.StatusBadRequest).SendString("Geçersiz ObjectId")
    }

    // GridFS'den dosya okuyun
    fsName := "go_files"
    bucket, err := gridfs.NewBucket(GetMongoDBClient().Database("fikoyt"), &options.BucketOptions{Name: &fsName})
    if err != nil {
        return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("GridFS bucket oluşturulamadı: %v", err))
    }

    stream, err := bucket.OpenDownloadStream(objectID)
    if err != nil {
        return c.Status(fiber.StatusNotFound).SendString(fmt.Sprintf("Dosya indirilemiyor: %v", err))
    }
    defer stream.Close()

    // Resmi decode et
    img, format, err := image.Decode(stream)
    if err != nil {
        // Eğer WebP formatında ise, onu decode etmek için webp.Decode kullan
        if webpImg, err := webp.Decode(stream); err == nil {
            img = webpImg
            format = "webp"
        } else {
            return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("Resim decode edilemedi: %v", err))
        }
    }

    // Efektler ve ayarlamalar
    boyut := c.Query("boyut")
    var width, height int
    if boyut != "" {
        dimensions := strings.Split(boyut, "x")
        if len(dimensions) == 2 {
            width, _ = strconv.Atoi(dimensions[0])
            height, _ = strconv.Atoi(dimensions[1])
        }
        if width > 0 && height > 0 {
            img = imaging.Resize(img, width, height, imaging.Lanczos)
        }
    }

    if c.Query("thumbnail") == "true" {
        img = imaging.Thumbnail(img, 150, 150, imaging.Lanczos)
    }

    if c.Query("grayscale") == "true" {
        img = imaging.Grayscale(img)
    }

    if blurRadiusStr := c.Query("blur"); blurRadiusStr != "" {
        blurRadius, _ := strconv.ParseFloat(blurRadiusStr, 64)
        if blurRadius > 0 {
            img = imaging.Blur(img, blurRadius)
        }
    }

    if rotateAngleStr := c.Query("rotate"); rotateAngleStr != "" {
        rotateAngle, _ := strconv.Atoi(rotateAngleStr)
        img = imaging.Rotate(img, float64(rotateAngle), color.Transparent)
    }

    if flip := c.Query("flip"); flip != "" {
        if flip == "horizontal" {
            img = imaging.FlipH(img)
        } else if flip == "vertical" {
            img = imaging.FlipV(img)
        }
    }

    if brightnessStr := c.Query("brightness"); brightnessStr != "" {
        brightness, _ := strconv.ParseFloat(brightnessStr, 64)
        if brightness != 0 {
            img = imaging.AdjustBrightness(img, brightness)
        }
    }

    if contrastStr := c.Query("contrast"); contrastStr != "" {
        contrast, _ := strconv.ParseFloat(contrastStr, 64)
        if contrast != 0 {
            img = imaging.AdjustContrast(img, contrast)
        }
    }

    if sharpnessStr := c.Query("sharpness"); sharpnessStr != "" {
        sharpness, _ := strconv.ParseFloat(sharpnessStr, 64)
        if sharpness != 0 {
            img = imaging.Sharpen(img, sharpness)
        }
    }

    if c.Query("sepia") == "true" {
        img = imaging.AdjustSaturation(img, -1)
        img = imaging.AdjustContrast(img, 30)
        img = imaging.AdjustBrightness(img, 20)
    }

    if saturationStr := c.Query("saturation"); saturationStr != "" {
        saturation, _ := strconv.ParseFloat(saturationStr, 64)
        if saturation != 0 {
            img = imaging.AdjustSaturation(img, saturation)
        }
    }

    if cropStr := c.Query("crop"); cropStr != "" {
        parts := strings.Split(cropStr, ",")
        if len(parts) == 4 {
            x, _ := strconv.Atoi(parts[0])
            y, _ := strconv.Atoi(parts[1])
            w, _ := strconv.Atoi(parts[2])
            h, _ := strconv.Atoi(parts[3])
            if w > 0 && h > 0 {
                img = imaging.Crop(img, image.Rect(x, y, x+w, y+h))
            }
        }
    }

    if c.Query("negative") == "true" {
        img = imaging.Invert(img)
    }

    if hueStr := c.Query("hue"); hueStr != "" {
        hue, _ := strconv.ParseFloat(hueStr, 64)
        if hue != 0 {
            img = imaging.AdjustSaturation(img, hue)
        }
    }

    // Watermark ekleme (şu an bir örnek yapılmadı)

    quality := 80 // Varsayılan kalite
    if qualityStr := c.Query("quality"); qualityStr != "" {
        parsedQuality, _ := strconv.Atoi(qualityStr)
        if parsedQuality > 0 && parsedQuality <= 100 {
            quality = parsedQuality
        }
    }

    // Yanıt içerik türünü ayarla
    contentType := "image/jpeg"
    if format == "png" {
        contentType = "image/png"
    } else if format == "webp" {
        contentType = "image/webp"
    }
    c.Set("Content-Type", contentType)

    // İşlenmiş resmi yanıt olarak gönder
    if contentType == "image/jpeg" {
        options := &jpeg.Options{Quality: quality}
        return jpeg.Encode(c.Response().BodyWriter(), img, options)
    } else if contentType == "image/png" {
        return png.Encode(c.Response().BodyWriter(), img)
    } else if contentType == "image/webp" {
        // WebP encoder'ı kullanıyoruz
        encoder := webp.NewEncoder(c.Response().BodyWriter(), img, &webp.Options{Quality: 80})
        return encoder.Encode()
    }

    return c.Status(fiber.StatusInternalServerError).SendString("Resim işlenemedi")
})

func setMiddleWare(app *fiber.App) {
	app.Use(func(c fiber.Ctx) error {
		ses, _ := GetSession().Get(c)
		c.Locals("session", ses)
		return c.Next()
	})
}

// Dinamik veriyi session'a kaydeden yardımcı fonksiyon
func SetSessionData(s *session.Session, key string, value interface{}) error {
	// Veriyi JSON'a dönüştürmeye çalışıyoruz
	data, err := json.Marshal(value)
	if err != nil {
		return fmt.Errorf("failed to marshal value: %v", err)
	}

	// Veriyi session'a kaydediyoruz
	s.Set(key, data)

	// Session'ı kaydediyoruz
	if err := s.Save(); err != nil {
		return fmt.Errorf("failed to save session: %v", err)
	}

	return nil
}

// Session'dan veriyi almak için yardımcı fonksiyon
func GetSessionData(s *session.Session, key string) (interface{}, error) {
	// Session'dan veriyi alıyoruz
	value := s.Get(key)
	if value == nil {
		return nil, fmt.Errorf("no value found for key: %s", key)
	}

	// Veriyi JSON'dan çözümleyip interface{} olarak döndürüyoruz
	data, ok := value.([]byte) // Veriyi []byte olarak aldığınızı varsayıyoruz
	if !ok {
		return nil, fmt.Errorf("expected []byte, got %T", value)
	}

	var result interface{}
	if err := json.Unmarshal(data, &result); err != nil {
		return nil, fmt.Errorf("failed to unmarshal session data: %v", err)
	}

	return result, nil
}
