package main

// USB surucu izleyicisi: Windows bir surucu takildiginda ya da cikarildiginda tetik gelir;
// izleyici suruculeri yeniden okur, farklari olay olarak yollar. Olaylar kullanici ayarina gore suzulur.
// Bu dosya platformdan bagimsizdir; Windows'a ozgu dinleyici ve tarama usb_windows.go icindedir.

import (
	"context"
)

// Surucu: takili cikarilabilir bir surucu (harf ve etiket).
type Surucu struct {
	Harf   string `json:"harf"`
	Etiket string `json:"etiket"`
}

// Mesaj: bridge'e giden tek satirlik JSON. Tip: "durum" | "olay" | "cevap" | "hata".
type Mesaj struct {
	Tip       string   `json:"tip"`
	Olay      string   `json:"olay,omitempty"`
	Surucu    *Surucu  `json:"surucu,omitempty"`
	Suruculer []Surucu `json:"suruculer,omitempty"`
	Tamam     bool     `json:"tamam,omitempty"`
	Hata      string   `json:"hata,omitempty"`
}

// Ayar: kullanicinin sectigi bildirim secenekleri. Bridge bu degerleri saklar ve eklentiye iletir.
type Ayar struct {
	TakmaBildir   bool `json:"takmaBildir"`
	CikarmaBildir bool `json:"cikarmaBildir"`
	EtiketGoster  bool `json:"etiketGoster"`
}

// varsayilanAyar: ayar hic verilmediginde tum bildirimler acik olur.
func varsayilanAyar() Ayar {
	return Ayar{TakmaBildir: true, CikarmaBildir: true, EtiketGoster: true}
}

// fark: onceki ve simdiki listeler arasinda takilan ve cikarilan suruculeri bulur.
func fark(onceki, simdi []Surucu) (takilan, cikarilan []Surucu) {
	eski := map[string]bool{}
	for _, s := range onceki {
		eski[s.Harf] = true
	}
	yeni := map[string]bool{}
	for _, s := range simdi {
		yeni[s.Harf] = true
	}
	for _, s := range simdi {
		if !eski[s.Harf] {
			takilan = append(takilan, s)
		}
	}
	for _, s := range onceki {
		if !yeni[s.Harf] {
			cikarilan = append(cikarilan, s)
		}
	}
	return takilan, cikarilan
}

// ayarlaUygula: bir olayi kullanici ayarina gore suzer. Gonderilmeyecekse false doner.
func ayarlaUygula(m Mesaj, a Ayar) (Mesaj, bool) {
	if m.Tip != "olay" {
		return m, true
	}
	if m.Olay == "takildi" && !a.TakmaBildir {
		return m, false
	}
	if m.Olay == "cikarildi" && !a.CikarmaBildir {
		return m, false
	}
	if !a.EtiketGoster && m.Surucu != nil {
		s := *m.Surucu
		s.Etiket = ""
		m.Surucu = &s
	}
	return m, true
}

// izle: once mevcut durumu yollar; sonra her tetikte suruculeri yeniden okur ve farklari olay olarak yollar.
// ayar aninda degisebilir: ayarAl her olay icin o anki ayari dondurur. ctx iptal edilince durur.
func izle(ctx context.Context, tara func() ([]Surucu, error), yaz func(Mesaj), tetik <-chan struct{}, ayarAl func() Ayar) {
	onceki, err := tara()
	if err != nil {
		onceki = nil
	}
	yaz(Mesaj{Tip: "durum", Suruculer: onceki})

	for {
		select {
		case <-ctx.Done():
			return
		case <-tetik:
			simdi, err := tara()
			if err != nil {
				continue
			}
			takilan, cikarilan := fark(onceki, simdi)
			a := ayarAl()
			for i := range takilan {
				s := takilan[i]
				if m, ok := ayarlaUygula(Mesaj{Tip: "olay", Olay: "takildi", Surucu: &s}, a); ok {
					yaz(m)
				}
			}
			for i := range cikarilan {
				s := cikarilan[i]
				if m, ok := ayarlaUygula(Mesaj{Tip: "olay", Olay: "cikarildi", Surucu: &s}, a); ok {
					yaz(m)
				}
			}
			onceki = simdi
		}
	}
}
