package api

import (
	"strings"
	"time"

	"github.com/gofiber/fiber/v2"
)

type healthResponse struct {
	Status        string      `json:"status"` // "ok" | "degraded"
	Env           string      `json:"env"`
	Version       string      `json:"version"`
	UptimeSeconds int64       `json:"uptimeSeconds"`
	Time          string      `json:"time"`
	WSPath        string      `json:"wsPath"`
	WSConnections int         `json:"wsConnections"`
	LLMProvider   string      `json:"llmProvider"`
	Voice         voiceHealth `json:"voice"`
}

// voiceHealth ses motorlarının bağlı olup olmadığını bildirir. Arayüz mikrofon ve
// hoparlör düğmelerini BUNA göre gösterir/gizler; yoksa kullanıcı çalışmayan bir
// düğmeye tıklayıp hata okumak zorunda kalır.
type voiceHealth struct {
	STT bool `json:"stt"` // sesli giriş (konuşma tanıma) motoru
	TTS bool `json:"tts"` // sesli çıkış (sesli okuma) motoru
}

// ---- Sistem durumu (GET /api/system) ----

/**
 * FeatureStatus tek bir özelliğin durumudur.
 *
 * Neden `enabled` + `configured` ayrı? Kullanıcının en çok sorduğu soru
 * "neden çalışmıyor?"dur. İki bilgi birlikte cevap verir:
 *   enabled=false  → sunucuda bilerek KAPALI (bilinçli tercih)
 *   configured=false → açılmak istendi ama eksik ayar var (örn. URL boş)
 * Arayüz bu ikisinden "ne yapmalıyım" ipucu üretir.
 */
type FeatureStatus struct {
	// Key özellik anahtarı (istemdeki env değişkeni ailesi).
	Key string `json:"key"`
	// Title insan dilinde ad.
	Title string `json:"title"`
	// Enabled sunucuda açık mı.
	Enabled bool `json:"enabled"`
	// Configured açık olmak için gereken ayarlar tam mı.
	Configured bool `json:"configured"`
	// Provider seçili motor (yoksa boş).
	Provider string `json:"provider,omitempty"`
	// Detail tek satırlık açıklama / eksik ayar adı.
	Detail string `json:"detail,omitempty"`
	// Hint kullanıcıya ne yapması gerektiğini söyler (yoksa boş).
	Hint string `json:"hint,omitempty"`
	// Group ekranda gruplandırma başlığıdır.
	Group string `json:"group"`
}

// systemResponse GET /api/system yanıtıdır: sunucunun yetenekleri ve anahtarları.
type systemResponse struct {
	Status   string          `json:"status"` // "ok" | "degraded"
	Env      string          `json:"env"`
	Version  string          `json:"version"`
	Features []FeatureStatus `json:"features"`
	// Permissions kullanıcının tool izin özeti (hangi düğmeler açık).
	Permissions *permissionsResponse `json:"permissions,omitempty"`
	// Auth kimlik doğrulama durumu. AuthEnabled=false ise sistem AÇIKTIR ve
	// X-Fiko-User taklit edilebilir; panelde uyarı gösterilir.
	Auth *authStatus `json:"auth,omitempty"`
}

// authStatus, kimlik doğrulama durumunu bildirir.
type authStatus struct {
	Enabled bool `json:"enabled"`
	// Users true ise üyelik (kayıt/giriş) sistemi AÇIKTIR: ön yüz kullanıcı adı + parola
	// ekranını gösterir ve oturum token'ı taşır.
	Users   bool   `json:"users"`
	Warning string `json:"warning,omitempty"`
	Header  string `json:"header,omitempty"`
}

// health GET /api/health — hazır kontrolü ve çalışma bilgisi.
// LLM sağlayıcısına istek yapmaz: kontrol ucu LLM'e bağımlı olmamalıdır.
func (s *Server) health(c *fiber.Ctx) error {
	resp := healthResponse{
		Status:        "ok",
		Env:           s.cfg.Env,
		Version:       s.cfg.Version,
		UptimeSeconds: int64(time.Since(s.started).Seconds()),
		Time:          time.Now().UTC().Format(time.RFC3339),
		WSPath:        WSPath,
	}
	if s.deps.LLM != nil {
		resp.LLMProvider = s.deps.LLM.Name()
	} else {
		resp.Status = "degraded"
	}
	if s.deps.Hub != nil {
		resp.WSConnections = s.deps.Hub.Count()
		// Ses motorları aynı hub üzerinden bağlanır; buradan bildirilir.
		resp.Voice = voiceHealth{STT: s.deps.Hub.HasSTT(), TTS: s.deps.Hub.HasTTS()}
	} else {
		// WS katmanı bağlı değilse sunucu eksiktir.
		resp.Status = "degraded"
	}
	return c.JSON(resp)
}

// systemStatus GET /api/system — sunucunun yetenekleri ve anahtarları.
//
// Bu uç SALT OKUNURDUR: hiçbir ayarı DEĞİŞTİRMEZ. Amaçları tek ekranda
// "ne açık, ne kapalı, ne eksik" sorusunu cevaplamaktır. Kullanıcı bir düğmeye
// tıklayıp neden çalışmadığını tahmin etmek zorunda kalmamalıdır.
//
// LLM'e istek YAPILMAZ (health ucu gibi): kontrol ucu sağlayıcıya bağımlı olmamalıdır.
func (s *Server) systemStatus(c *fiber.Ctx) error {
	resp := systemResponse{
		Status:   "ok",
		Env:      s.cfg.Env,
		Version:  s.cfg.Version,
		Features: append([]FeatureStatus(nil), s.cfg.System...),
	}
	// LLM/WS yoksa sistem eksiktir; kullanıcı bunu listeden değil, göstergeden görür.
	if s.deps.LLM == nil || s.deps.Hub == nil {
		resp.Status = "degraded"
	}
	// Kimlik doğrulama durumu: anahtar yoksa sistem açıktır ve kullanıcı
	// taklit edilebilir. Bunu gizlemek yerine AÇIKÇA bildiriyoruz.
	resp.Auth = &authStatus{
		Enabled: strings.TrimSpace(s.cfg.AuthKey) != "",
		Users:   s.cfg.UsersEnabled && s.deps.Users != nil,
		Header:  AuthHeader,
	}
	if !resp.Auth.Enabled && !resp.Auth.Users {
		resp.Auth.Warning = "Kimlik doğrulama KAPALI: FIKO_API_KEY tanımlı değil. " +
			"X-Fiko-User başlığıyla herhangi bir kullanıcı kimliği taklit edilebilir. " +
			"Yalnızca yerel/izole ağda kullanın."
	}

	// İzin özeti: paneldeki "yazma/silme düğmeleri neden kilitli?" sorusunu cevaplar.
	// Üyelik açıkken bu uca anonim de erişilebilir; izin özeti (ve özel politikası olan üye
	// kimlikleri) yalnızca oturumu olana gösterilir.
	if s.deps.Grants != nil && (!s.cfg.UsersEnabled || c.Locals(localsUserID) != nil) {
		uid := s.currentUser(c)
		p := s.permissionsFor(c, uid)
		resp.Permissions = &p
	}
	return c.JSON(resp)
}
