package kokDB

import (
	"math"
	"strings"
	"sync"

	"server/sistem/FikoYTDosya"
	FikoYTCtx "server/sistem/fikoyt_ctx"
	FikoYTMap "server/sistem/fikoyt_map"
	"server/sistem/socket_ortak"

	"github.com/zishang520/socket.io/v2/socket"
	"go.mongodb.org/mongo-driver/mongo"
)

// Paylaşım kartı değişiklik olayı — tüm bağlı istemcilere yayınlanır
const paylasimKartOlayi = "FikoYT.paylasim.kart.degisti"

// paylasimVtMi: yalnızca paylaşım kartı yazımları yayınlanır.
// vt alanı yoksa (ör. soft-delete {_id, silindi:true}) yayın yapılır.
func paylasimVtMi(m FikoYTMap.FikoYTMap) bool {
	if m == nil {
		return true
	}
	if vt, ok := m["vt"].(string); ok && vt != "" {
		return vt == "FikoYT.sistem.hareketler"
	}
	return true
}

// paylasimKartYayinla: kart değişikliğini Socket.IO üzerinden duyurur (fire-and-forget)
func paylasimKartYayinla(FikoYT *FikoYTCtx.FikoYTCtx, tip string, kartId string) {
	if socket_ortak.FikoSocketIo == nil {
		return
	}
	kaynakKid := ""
	if oid, ok := aktifKullaniciOid(FikoYT); ok {
		kaynakKid = oid.Hex()
	}
	veri := map[string]interface{}{
		"tip":       tip, // "yeni" | "guncellendi" | "silindi"
		"kartId":    kartId,
		"kaynakKid": kaynakKid,
	}
	go socket_ortak.FikoSocketIo.FetchSockets()(func(sockets []*socket.RemoteSocket, err error) {
		if err != nil {
			return
		}
		for _, s := range sockets {
			s.Emit(paylasimKartOlayi, veri)
		}
	})
}

// ekleSonrasiYayinla: ekle (upsert) sonucunu yorumlayıp uygun kart olayını yayınlar
func ekleSonrasiYayinla(FikoYT *FikoYTCtx.FikoYTCtx, json FikoYTMap.FikoYTMap, sonuc interface{}) {
	if !paylasimVtMi(json) {
		return
	}
	// İfade/beğeni kaydı: kartın kendisi değil, veri alanı hedef kartı gösterir
	if yol, _ := json["yol"].(string); strings.HasSuffix(yol, ".ifade") || strings.HasSuffix(yol, ".begen") {
		if hedef := objectIdToHex(json["veri"]); hedef != "" {
			paylasimKartYayinla(FikoYT, "guncellendi", hedef)
			return
		}
	}
	tip := "guncellendi"
	kartId := objectIdToHex(json["_id"])
	if rs, ok := sonuc.([]*mongo.UpdateResult); ok && len(rs) > 0 && rs[0] != nil && rs[0].UpsertedID != nil {
		tip = "yeni"
		if kartId == "" {
			kartId = objectIdToHex(rs[0].UpsertedID)
		}
	}
	if s, ok := json["silindi"].(bool); ok && s {
		tip = "silindi"
	}
	if kartId == "" {
		return
	}
	// Alt kayıt (içerik/yorum) yazımı: üst kart da değişti — alıcılar tam kartı yeniden çeksin
	if uid := objectIdToHex(json["_uid"]); uid != "" && uid != kartId {
		paylasimKartYayinla(FikoYT, "guncellendi", uid)
	}
	paylasimKartYayinla(FikoYT, tip, kartId)
}

// Dosya işleme ilerlemesi (sıkıştırma / thumbnail / kaydetme) olayı
const dosyaIslemOlayi = "FikoYT.dosya.islem"

// dosyaIslemYayinci: bir yükleme isteğinin dosya olaylarını Socket.IO'ya çevirir.
// Aynı yüzdeyi tekrar tekrar yollamamak için son gönderileni tutar (ffmpeg satır satır ilerler).
type dosyaIslemYayinci struct {
	mu     sync.Mutex
	kartId string
	son    float64
}

// dosyaIslemDurumu: olayı genel yüzde (0-100) ve aşama adına çevirir
func dosyaIslemDurumu(e *FikoYTDosya.ProcessEvent) (asama string, yuzde float64, durum string, ok bool) {
	switch e.Type {
	case FikoYTDosya.EventCompressionStart:
		return "sikistirma", 10, "devam", true
	case FikoYTDosya.EventProgress:
		if e.ProcessStep == "COMPRESSION" {
			// ffmpeg ilerlemesi genel %10-%60 aralığına eşlenir
			return "sikistirma", math.Min(10+e.Progress*0.5, 60), "devam", true
		}
	case FikoYTDosya.EventCompressionEnd:
		return "sikistirma", 60, "devam", true
	case FikoYTDosya.EventThumbnailStart:
		return "thumbnail", 70, "devam", true
	case FikoYTDosya.EventThumbnailEnd:
		return "thumbnail", 90, "devam", true
	case FikoYTDosya.EventGridFSSave:
		return "kaydetme", 92, "devam", true
	case FikoYTDosya.EventCompleted:
		switch e.ProcessStep {
		case "GRIDFS_SAVE":
			return "kaydetme", 97, "devam", true
		case "THUMB_GRIDFS_SAVE":
			return "kaydetme", 99, "devam", true
		case "CLEANUP":
			return "tamamlandi", 100, "tamamlandi", true
		}
	case FikoYTDosya.EventError:
		return "hata", 0, "hata", true
	}
	return "", 0, "", false
}

// Olay geldiğinde uygun ise Socket.IO ile tüm istemcilere yayınlar
func (y *dosyaIslemYayinci) Yayinla(e *FikoYTDosya.ProcessEvent) {
	asama, yuzde, durum, ok := dosyaIslemDurumu(e)
	if !ok || socket_ortak.FikoSocketIo == nil {
		return
	}

	y.mu.Lock()
	yuvarlak := math.Floor(yuzde)
	if durum == "devam" && yuvarlak == y.son {
		y.mu.Unlock()
		return
	}
	y.son = yuvarlak
	y.mu.Unlock()

	// Karta erişimi olan istemciler kendi ekranlarındaki kartla eşleştirir (kartId).
	// Sadece ilerleme yüzdesi ve kimlikler taşınır; kart içeriği taşınmaz.
	veri := map[string]interface{}{
		"kartId":    y.kartId,
		"dosyaId":   e.FileID.Hex(),
		"asama":     asama,
		"yuzde":     yuzde,
		"durum":     durum,
		"mesaj":     e.Message,
	}
	go socket_ortak.FikoSocketIo.FetchSockets()(func(sockets []*socket.RemoteSocket, err error) {
		if err != nil {
			return
		}
		for _, s := range sockets {
			s.Emit(dosyaIslemOlayi, veri)
		}
	})
}
