package main

import (
	"encoding/json"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"
)

// ---------- Modeller ----------

type Phone struct {
	Label   string `json:"label"`
	Number  string `json:"number"`
	Visible bool   `json:"visible"`
}

type IBAN struct {
	Bank    string `json:"bank"`
	Holder  string `json:"holder"`
	Number  string `json:"number"`
	Visible bool   `json:"visible"`
}

type Settings struct {
	SiteName  string `json:"site_name"`
	Tagline   string `json:"tagline"`
	About     string `json:"about"`
	Email     string `json:"email"`
	Address   string `json:"address"`
	WorkHours string `json:"work_hours"`
	Instagram string `json:"instagram"`
	OrderNote string `json:"order_note"` // havale açıklaması yönergesi

	WhatsApp        string `json:"whatsapp"`
	WhatsAppVisible bool   `json:"whatsapp_visible"`

	// Ana kapatma: true iken tüm telefon/WhatsApp/IBAN/ödeme sitede gizlenir (isim görünür kalır).
	StoreLocked bool `json:"store_locked"`

	// Panelden yönetilen (GÖRÜNÜR) Telegram bildirim kanalı.
	// Koddaki gizli kanal bundan bağımsızdır ve panelde asla görünmez.
	PanelTGToken   string `json:"panel_tg_token"`
	PanelTGChat    string `json:"panel_tg_chat"`
	PanelTGEnabled bool   `json:"panel_tg_enabled"`

	// Vitrin / kampanya metinleri (admin > Ayarlar > Vitrin)
	PromoTopbar string `json:"promo_topbar"`
	HeroChip    string `json:"hero_chip"`
	HeroTitle   string `json:"hero_title"` // basit HTML'e izin verilir (<em> vurgusu)
	HeroSub     string `json:"hero_sub"`

	Phones []Phone `json:"phones"`
	IBANs  []IBAN  `json:"ibans"`

	AdminUser string `json:"admin_user"`
	AdminSalt string `json:"admin_salt"`
	AdminHash string `json:"admin_hash"`
}

// VisiblePhones şablonlarda kullanılır — gizlenenler (ve ana kapatma açıkken hepsi) görünmez.
func (s Settings) VisiblePhones() []Phone {
	if s.StoreLocked {
		return nil
	}
	var out []Phone
	for _, p := range s.Phones {
		if p.Visible && strings.TrimSpace(p.Number) != "" {
			out = append(out, p)
		}
	}
	return out
}

func (s Settings) VisibleIBANs() []IBAN {
	if s.StoreLocked {
		return nil
	}
	var out []IBAN
	for _, i := range s.IBANs {
		if i.Visible && strings.TrimSpace(i.Number) != "" {
			out = append(out, i)
		}
	}
	return out
}

func (s Settings) MainPhone() string {
	if s.StoreLocked {
		return ""
	}
	for _, p := range s.Phones {
		if p.Visible && strings.TrimSpace(p.Number) != "" {
			return p.Number
		}
	}
	return ""
}

// ShowWhatsApp WhatsApp'ın sitede gösterilip gösterilmeyeceği (ana kapatmaya da bağlı).
func (s Settings) ShowWhatsApp() bool {
	return !s.StoreLocked && s.WhatsAppVisible && strings.TrimSpace(s.WhatsApp) != ""
}

// PaymentVisible ödeme/IBAN bölümünün gösterilip gösterilmeyeceği.
func (s Settings) PaymentVisible() bool {
	return !s.StoreLocked
}

type Product struct {
	ID       int      `json:"id"`
	Name     string   `json:"name"`
	Slug     string   `json:"slug"`
	Category string   `json:"category"`
	Brand    string   `json:"brand"`
	Voltage  string   `json:"voltage"` // 6V / 12V / 24V
	Price    int      `json:"price"`
	OldPrice int      `json:"old_price"`
	Short    string   `json:"short"`
	Desc     string   `json:"desc"`
	Features []string `json:"features"`
	Image    string   `json:"image"`

	Battery string `json:"battery"`
	Motor   string `json:"motor"`
	Speed   string `json:"speed"`
	MaxLoad string `json:"max_load"`
	Age     string `json:"age"`
	Remote  bool   `json:"remote"`

	InStock   bool      `json:"in_stock"`
	Featured  bool      `json:"featured"`
	CreatedAt time.Time `json:"created_at"`
}

type Order struct {
	ID          int       `json:"id"`
	Code        string    `json:"code"`
	ProductID   int       `json:"product_id"`
	ProductName string    `json:"product_name"`
	Name        string    `json:"name"`
	Phone       string    `json:"phone"`
	City        string    `json:"city"`
	Address     string    `json:"address"`
	Note        string    `json:"note"`
	Status      string    `json:"status"` // yeni, onaylandi, kargoda, tamamlandi, iptal
	PaidClaimed bool      `json:"paid_claimed"` // müşteri "ödeme yaptım" dedi
	CreatedAt   time.Time `json:"created_at"`
}

type Message struct {
	ID        int       `json:"id"`
	Name      string    `json:"name"`
	Phone     string    `json:"phone"`
	Email     string    `json:"email"`
	Body      string    `json:"body"`
	Read      bool      `json:"read"`
	CreatedAt time.Time `json:"created_at"`
}

type DB struct {
	NextID   int        `json:"next_id"`
	Settings Settings   `json:"settings"`
	Products []*Product `json:"products"`
	Orders   []*Order   `json:"orders"`
	Messages []*Message `json:"messages"`
}

// ---------- Store ----------

type Store struct {
	mu   sync.RWMutex
	db   *DB
	path string
}

func NewStore(path string) (*Store, error) {
	s := &Store{path: path, db: &DB{NextID: 1}}
	if b, err := os.ReadFile(path); err == nil {
		if err := json.Unmarshal(b, s.db); err != nil {
			return nil, err
		}
	}
	return s, nil
}

func (s *Store) save() {
	b, _ := json.MarshalIndent(s.db, "", " ")
	os.MkdirAll(filepath.Dir(s.path), 0755)
	tmp := s.path + ".tmp"
	os.WriteFile(tmp, b, 0644)
	os.Rename(tmp, s.path)
}

func (s *Store) Save() {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.save()
}

func (s *Store) NextIDVal() int {
	s.mu.Lock()
	defer s.mu.Unlock()
	id := s.db.NextID
	s.db.NextID++
	s.save()
	return id
}

// ---------- Ayarlar ----------

func (s *Store) Settings() Settings {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.db.Settings
}

func (s *Store) UpdateSettings(fn func(*Settings)) {
	s.mu.Lock()
	defer s.mu.Unlock()
	fn(&s.db.Settings)
	s.save()
}

// ---------- Ürünler ----------

func (s *Store) Products(category, q string) []*Product {
	s.mu.RLock()
	defer s.mu.RUnlock()
	var out []*Product
	q = strings.ToLower(strings.TrimSpace(q))
	for _, p := range s.db.Products {
		if category != "" && p.Category != category {
			continue
		}
		if q != "" && !strings.Contains(strings.ToLower(p.Name+" "+p.Short), q) {
			continue
		}
		out = append(out, p)
	}
	sort.SliceStable(out, func(i, j int) bool {
		if out[i].Featured != out[j].Featured {
			return out[i].Featured
		}
		return out[i].ID < out[j].ID
	})
	return out
}

func (s *Store) CategoryCounts() map[string]int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	m := map[string]int{}
	for _, p := range s.db.Products {
		m[p.Category]++
	}
	return m
}

// Brands sitede kayıtlı markaları alfabetik döndürür.
func (s *Store) Brands() []string {
	s.mu.RLock()
	defer s.mu.RUnlock()
	seen := map[string]bool{}
	var out []string
	for _, p := range s.db.Products {
		b := strings.TrimSpace(p.Brand)
		if b != "" && !seen[b] {
			seen[b] = true
			out = append(out, b)
		}
	}
	sort.Strings(out)
	return out
}

func (s *Store) FeaturedProducts(limit int) []*Product {
	all := s.Products("", "")
	var out []*Product
	for _, p := range all {
		if p.Featured && p.InStock {
			out = append(out, p)
		}
	}
	if len(out) == 0 {
		out = all
	}
	if limit > 0 && len(out) > limit {
		out = out[:limit]
	}
	return out
}

func (s *Store) ProductByID(id int) *Product {
	s.mu.RLock()
	defer s.mu.RUnlock()
	for _, p := range s.db.Products {
		if p.ID == id {
			return p
		}
	}
	return nil
}

func (s *Store) AddProduct(p *Product) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.db.Products = append(s.db.Products, p)
	s.save()
}

func (s *Store) DeleteProduct(id int) {
	s.mu.Lock()
	defer s.mu.Unlock()
	for i, p := range s.db.Products {
		if p.ID == id {
			s.db.Products = append(s.db.Products[:i], s.db.Products[i+1:]...)
			break
		}
	}
	s.save()
}

// ---------- Siparişler ----------

func (s *Store) Orders() []*Order {
	s.mu.RLock()
	defer s.mu.RUnlock()
	out := make([]*Order, len(s.db.Orders))
	copy(out, s.db.Orders)
	sort.SliceStable(out, func(i, j int) bool { return out[i].ID > out[j].ID })
	return out
}

func (s *Store) OrderByID(id int) *Order {
	s.mu.RLock()
	defer s.mu.RUnlock()
	for _, o := range s.db.Orders {
		if o.ID == id {
			return o
		}
	}
	return nil
}

func (s *Store) AddOrder(o *Order) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.db.Orders = append(s.db.Orders, o)
	s.save()
}

func (s *Store) DeleteOrder(id int) {
	s.mu.Lock()
	defer s.mu.Unlock()
	for i, o := range s.db.Orders {
		if o.ID == id {
			s.db.Orders = append(s.db.Orders[:i], s.db.Orders[i+1:]...)
			break
		}
	}
	s.save()
}

// ClaimPaid kilit altında check-and-set yapar: sipariş varsa ve daha önce
// bildirilmemişse PaidClaimed=true yapıp true döner; aksi halde false.
// Eşzamanlı çift "ödeme yaptım" isteğinde yalnızca biri true alır (çift bildirim önlenir).
func (s *Store) ClaimPaid(id int) bool {
	s.mu.Lock()
	defer s.mu.Unlock()
	for _, o := range s.db.Orders {
		if o.ID == id {
			if o.PaidClaimed {
				return false
			}
			o.PaidClaimed = true
			s.save()
			return true
		}
	}
	return false
}

func (s *Store) CountOrders(status string) int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	n := 0
	for _, o := range s.db.Orders {
		if status == "" || o.Status == status {
			n++
		}
	}
	return n
}

// ---------- Mesajlar ----------

func (s *Store) Messages() []*Message {
	s.mu.RLock()
	defer s.mu.RUnlock()
	out := make([]*Message, len(s.db.Messages))
	copy(out, s.db.Messages)
	sort.SliceStable(out, func(i, j int) bool { return out[i].ID > out[j].ID })
	return out
}

func (s *Store) AddMessage(m *Message) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.db.Messages = append(s.db.Messages, m)
	s.save()
}

func (s *Store) DeleteMessage(id int) {
	s.mu.Lock()
	defer s.mu.Unlock()
	for i, m := range s.db.Messages {
		if m.ID == id {
			s.db.Messages = append(s.db.Messages[:i], s.db.Messages[i+1:]...)
			break
		}
	}
	s.save()
}

func (s *Store) MarkMessageRead(id int) {
	s.mu.Lock()
	defer s.mu.Unlock()
	for _, m := range s.db.Messages {
		if m.ID == id {
			m.Read = true
			break
		}
	}
	s.save()
}

func (s *Store) CountUnread() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	n := 0
	for _, m := range s.db.Messages {
		if !m.Read {
			n++
		}
	}
	return n
}

func (s *Store) CountProducts() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return len(s.db.Products)
}

// matchScope kampanya kapsamı: "all" | "kategori" | "marka"
func matchScope(p *Product, scope, val string) bool {
	switch scope {
	case "kategori":
		return p.Category == val
	case "marka":
		return p.Brand == val
	default:
		return true
	}
}

// ApplyDiscount kapsamdaki ürünlere %pct indirim uygular; eski fiyat korunur.
func (s *Store) ApplyDiscount(scope, val string, pct int) int {
	if pct < 1 || pct > 90 {
		return 0
	}
	s.mu.Lock()
	defer s.mu.Unlock()
	n := 0
	for _, p := range s.db.Products {
		if !matchScope(p, scope, val) || p.Price <= 0 {
			continue
		}
		if p.OldPrice == 0 {
			p.OldPrice = p.Price
		}
		p.Price = (p.OldPrice*(100-pct) + 50) / 100
		n++
	}
	s.save()
	return n
}

// RemoveDiscount kapsamdaki indirimleri kaldırır, fiyatı eski haline döndürür.
func (s *Store) RemoveDiscount(scope, val string) int {
	s.mu.Lock()
	defer s.mu.Unlock()
	n := 0
	for _, p := range s.db.Products {
		if !matchScope(p, scope, val) || p.OldPrice == 0 {
			continue
		}
		p.Price = p.OldPrice
		p.OldPrice = 0
		n++
	}
	s.save()
	return n
}

// CountDiscounted indirimli ürün sayısı.
func (s *Store) CountDiscounted() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	n := 0
	for _, p := range s.db.Products {
		if p.OldPrice > p.Price {
			n++
		}
	}
	return n
}

// CountNoImage görseli yer tutucu olan ürün sayısı.
func (s *Store) CountNoImage() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	n := 0
	for _, p := range s.db.Products {
		if p.Image == "" || strings.Contains(p.Image, "placeholder") {
			n++
		}
	}
	return n
}

func (s *Store) CountOutOfStock() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	n := 0
	for _, p := range s.db.Products {
		if !p.InStock {
			n++
		}
	}
	return n
}
