package kok

import (
	"context"
	"crypto/hmac"
	"crypto/sha256"
	"fmt"
	"image"
	"image/color"
	"image/jpeg"
	"image/png"
	"regexp"
	FikoYTCtx "server/sistem/fikoyt_ctx"
	FikoYTHata "server/sistem/fikoyt_ctx/fikoyt_hata"
	FikoYTMap "server/sistem/fikoyt_map"
	fiko_mongo "server/sistem/fikoyt_mongo"
	"strconv"
	"strings"
	"time"

	"github.com/disintegration/imaging"
	"github.com/gofiber/contrib/monitor"
	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/middleware/session"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/gridfs"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func KokRouting(app *fiber.App) {

	app.Get("/", func(c fiber.Ctx) error {
		// panic("asdasda")
		// user := c.Locals("FikoYT").(fiber.Map)
		session := c.Locals("session").(*session.Session)

		s, err := fiko_mongo.GetSessionData(session, "test")
		if err != nil {

		}

		return c.Status(200).JSON(s)
	})
	///
	app.Get("/metrics", monitor.New(monitor.Config{Title: "FikoYT Metrikler"}))

	///
	app.Post("/fapi/fikoyt.com.FikoYT.sistem.Uye.Ol", func(c fiber.Ctx) error {
		FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)

		// if len(FikoYT.Istek.Dosyalar) > 0 {
		// 	dosya := FikoYT.Istek.Dosyalar[0]
		// 	dosya.Kaydet()
		// 	dosya.Isle()
		// 	dosya.KaydetGridFs(fiber.Map{"test": "deneme"})
		// 	dosya.TemizleDosyalar()
		// }

		// if true {
		// 	return nil
		// }

		// Birden fazla hata örneği
		if FikoYT.Istek.Json["anlasma"] == false {
			FikoYT.Cevap.Durum.Hatalar.Ekle(FikoYTHata.YeniFikoYTHataAnlasmaOnaylama().FikoYTHata)
		}
		///
		epostaPattern := `^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$`
		matched, _ := regexp.MatchString(epostaPattern, FikoYT.Istek.Json["ePosta"].(string))
		if !matched {
			FikoYT.Cevap.Durum.Hatalar.Ekle(FikoYTHata.YeniFikoYTHataTurHatasi("E-Posta").FikoYTHata)
		}
		///
		if FikoYT.Istek.Json["parola"] != FikoYT.Istek.Json["parolaTekrar"] {
			if FikoYT.Istek.Json["parola"] != "" || FikoYT.Istek.Json["parolaTekrar"] != "" {
				FikoYT.Cevap.Durum.Hatalar.Ekle(FikoYTHata.YeniFikoYTHataAyniDegilHatasi("Parola", "Parola Tekrar", nil).FikoYTHata)
			}
		}
		///
		kullaniciAdi := FikoYT.Istek.Json["kullaniciAdi"]
		goUyeler := FikoYT.Koleksiyon("goUyeler")
		if kullaniciAdi != nil {
			var kytUye FikoYTMap.FikoYTMap
			_ = goUyeler.FindOne(context.TODO(), fiber.Map{"kullaniciAdi": kullaniciAdi}).Decode(&kytUye)
			if kytUye != nil {
				FikoYT.Cevap.Durum.Hatalar.Ekle(FikoYTHata.YeniFikoYTHataKullaniciMevcutHatasi(kullaniciAdi.(string), nil).FikoYTHata)
			}
		}
		///
		eposta := FikoYT.Istek.Json["ePosta"]
		if eposta != nil {
			var kytEposta FikoYTMap.FikoYTMap
			_ = goUyeler.FindOne(context.TODO(), fiber.Map{"ePosta": eposta}).Decode(&kytEposta)
			if kytEposta != nil {
				FikoYT.Cevap.Durum.Hatalar.Ekle(FikoYTHata.YeniFikoYTHataEPostaMevcutHatasi(eposta.(string), nil).FikoYTHata)
			}
		}
		///

		if len(FikoYT.Cevap.Durum.Hatalar) > 0 {
			FikoYT.Cevap.AyarlaDurumKodu(499)
			FikoYT.Cevap.Durum.Hata = true

			return nil
		}

		///
		// FikoYT.Cevap.Sonuc = nil
		FikoYT.Cevap.AyarlaDurumKodu(200)

		FikoYT.Istek.Json["aktifDurum"] = "Aktif"

		FikoYT.Istek.Json["parola"] = parolaSifrele(FikoYT.Istek.Json["parola"].(string))
		delete(FikoYT.Istek.Json, "parolaTekrar")

		epostaOnayKodu := epostaOnayKoduFonksiyonu(FikoYT.Istek.Json["isim"].(string), FikoYT.Istek.Json["soyIsim"].(string), FikoYT.Istek.Json["kullaniciAdi"].(string))

		FikoYT.Istek.Json["epostaOnayKodu"] = epostaOnayKodu

		rslt, _ :=
			goUyeler.InsertOne(context.TODO(), FikoYT.Istek.Json)

		if len(FikoYT.Istek.Dosyalar) > 0 {
			dosya := FikoYT.Istek.Dosyalar[0]
			dosya.Kaydet()
			dosya.Isle()
			dosya.KaydetGridFs(fiber.Map{"yol": "./profilResimleri", "kid": rslt.InsertedID})
			dosya.TemizleDosyalar()
		}
		FikoYT.Cevap.Sonuc = true

		return c.Status(200).JSON(true)
	},
	)

	app.Get("/fikoyt.com.FikoYT.sistem.dosyalar.:id.resim", gridFsServeFile)
}

func serveStaticImage(c fiber.Ctx) error {
	// Serve a static image file (example: "static/placeholder.jpg")
	return c.SendFile("static/placeholder.jpg")
}

func gridFsServeFile(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(fiko_mongo.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 oku
	img, format, err := image.Decode(stream)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("Resim decode edilemedi: %v", err))
	}

	// Efektler ve ayarlamalar
	// Boyutlandırma
	boyut := c.Query("boyut")
	var width, height int
	if boyut != "" {
		dimensions := strings.Split(boyut, "x")

		// Eğer her iki boyut verilmişse
		if len(dimensions) == 2 {
			// Bir boyut "?" olabilir
			if dimensions[0] == "?" {
				// Yalnızca yükseklik verildi, genişlik hesaplanacak
				height, _ = strconv.Atoi(dimensions[1])
				imgWidth := img.Bounds().Dx()
				imgHeight := img.Bounds().Dy()
				aspectRatio := float64(imgWidth) / float64(imgHeight)
				width = int(float64(height) * aspectRatio)
			} else if dimensions[1] == "?" {
				// Yalnızca genişlik verildi, yükseklik hesaplanacak
				width, _ = strconv.Atoi(dimensions[0])
				imgWidth := img.Bounds().Dx()
				imgHeight := img.Bounds().Dy()
				aspectRatio := float64(imgHeight) / float64(imgWidth)
				height = int(float64(width) * aspectRatio)
			} else {
				// Hem genişlik hem de yükseklik verildi
				width, _ = strconv.Atoi(dimensions[0])
				height, _ = strconv.Atoi(dimensions[1])
			}
		} else if len(dimensions) == 1 {
			// Sadece bir boyut verildiyse, diğer boyut orantılı olarak hesaplanacak
			if strings.Contains(dimensions[0], "?") {
				// ? işareti var, orantılı olarak hesaplanacak
				if strings.Contains(dimensions[0], "x") {
					height = -1
					width, _ = strconv.Atoi(strings.Replace(dimensions[0], "?", "", 1))
				} else {
					width = -1
					height, _ = strconv.Atoi(strings.Replace(dimensions[0], "?", "", 1))
				}
			} else {
				// Eğer tek bir boyut verildiyse, her iki boyut eşit olacak şekilde ayarlanacak
				width, _ = strconv.Atoi(dimensions[0])
				height = width
			}
		}

		// Resmin orijinal boyutları
		imgWidth := img.Bounds().Dx()
		imgHeight := img.Bounds().Dy()

		// Boyutlandırma işlemi
		if width > 0 && height > 0 {
			img = imaging.Resize(img, width, height, imaging.Lanczos)
		} else if width > 0 && height == -1 {
			// Sadece width verildi, orantılı olarak height hesaplanacak
			aspectRatio := float64(imgHeight) / float64(imgWidth)
			height = int(float64(width) * aspectRatio)
			img = imaging.Resize(img, width, height, imaging.Lanczos)
		} else if height > 0 && width == -1 {
			// Sadece height verildi, orantılı olarak width hesaplanacak
			aspectRatio := float64(imgWidth) / float64(imgHeight)
			width = int(float64(height) * aspectRatio)
			img = imaging.Resize(img, width, height, imaging.Lanczos)
		}
	}

	// Thumbnail oluşturma
	if c.Query("thumbnail") == "true" {
		img = imaging.Thumbnail(img, 150, 150, imaging.Lanczos)
	}

	// Grayscale
	if c.Query("grayscale") == "true" {
		img = imaging.Grayscale(img)
	}

	// Blur
	if blurRadiusStr := c.Query("blur"); blurRadiusStr != "" {
		blurRadius, _ := strconv.ParseFloat(blurRadiusStr, 64)
		if blurRadius > 0 {
			img = imaging.Blur(img, blurRadius)
		}
	}

	// Rotate
	if rotateAngleStr := c.Query("rotate"); rotateAngleStr != "" {
		rotateAngle, _ := strconv.Atoi(rotateAngleStr)
		img = imaging.Rotate(img, float64(rotateAngle), color.Transparent)
	}

	// Flip
	if flip := c.Query("flip"); flip != "" {
		if flip == "horizontal" {
			img = imaging.FlipH(img)
		} else if flip == "vertical" {
			img = imaging.FlipV(img)
		}
	}

	// Brightness
	if brightnessStr := c.Query("brightness"); brightnessStr != "" {
		brightness, _ := strconv.ParseFloat(brightnessStr, 64)
		if brightness != 0 {
			img = imaging.AdjustBrightness(img, brightness)
		}
	}

	// Contrast
	if contrastStr := c.Query("contrast"); contrastStr != "" {
		contrast, _ := strconv.ParseFloat(contrastStr, 64)
		if contrast != 0 {
			img = imaging.AdjustContrast(img, contrast)
		}
	}

	// Sharpness
	if sharpnessStr := c.Query("sharpness"); sharpnessStr != "" {
		sharpness, _ := strconv.ParseFloat(sharpnessStr, 64)
		if sharpness != 0 {
			img = imaging.Sharpen(img, sharpness)
		}
	}

	// Sepia
	if c.Query("sepia") == "true" {
		img = imaging.AdjustSaturation(img, -1)
		img = imaging.AdjustContrast(img, 30)
		img = imaging.AdjustBrightness(img, 20)
	}

	// Saturation
	if saturationStr := c.Query("saturation"); saturationStr != "" {
		saturation, _ := strconv.ParseFloat(saturationStr, 64)
		if saturation != 0 {
			img = imaging.AdjustSaturation(img, saturation)
		}
	}

	// Crop
	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))
			}
		}
	}

	// Negative
	if c.Query("negative") == "true" {
		img = imaging.Invert(img)
	}

	// Hue Rotation
	if hueStr := c.Query("hue"); hueStr != "" {
		hue, _ := strconv.ParseFloat(hueStr, 64)
		if hue != 0 {
			img = imaging.AdjustSaturation(img, hue)
		}
	}

	// Watermark ekleme
	if watermarkStr := c.Query("watermark"); watermarkStr != "" {
		// Henüz bir watermark ekleme örneği yapılmadı, ancak overlay işlemi burada yapılabilir.
	}

	// Sıkıştırma işlemleri (JPEG kalitesi)
	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"
	}
	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)
	}

	return c.Status(fiber.StatusInternalServerError).SendString("Resim işlenemedi")

}

func epostaOnayKoduFonksiyonu(ad, soyad, kullaniciAdi string) string {
	// Bugün tarihine 1 gün ekleyelim
	a := time.Now().Add(24 * time.Hour)

	// Verileri birleştir
	dataToHash := ad + " " + soyad + kullaniciAdi + a.String()

	// Gizli anahtar (bu anahtar sizin tarafınızdan belirlenmeli)
	secretKey := []byte("FikoYT+1299")

	// HMAC-SHA256 kullanarak veri hashing
	hash := hmac.New(sha256.New, secretKey)
	hash.Write([]byte(dataToHash))
	hashedCode := hash.Sum(nil)

	// Hash kodu hex formatında döndürüyoruz
	return fmt.Sprintf("%x", hashedCode)
}

func parolaSifrele(parola string) string {
	// Verileri birleştir
	dataToHash := parola

	// Gizli anahtar (bu anahtar sizin tarafınızdan belirlenmeli)
	secretKey := []byte("FikoYT+1299")

	// HMAC-SHA256 kullanarak veri hashing
	hash := hmac.New(sha256.New, secretKey)
	hash.Write([]byte(dataToHash))
	hashedCode := hash.Sum(nil)

	// Hash kodu hex formatında döndürüyoruz
	return fmt.Sprintf("%x", hashedCode)
}

// HMAC ile Parola Doğrulama
func ParolaDogrula(parola, storedHash string) bool {
	// Gizli anahtar (bunu gerçek bir uygulamada gizli tutun)
	secretKey := []byte("FikoYT+1299")

	// Parolayı HMAC-SHA256 ile hash'le
	hash := hmac.New(sha256.New, secretKey)
	hash.Write([]byte(parola))
	calculatedHash := fmt.Sprintf("%x", hash.Sum(nil))

	// Hash'leri karşılaştır
	return storedHash == calculatedHash
}
