package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"archivmail/internal/audit"
	"archivmail/internal/storage"
	"archivmail/internal/tenantstore"
)

// handleGetTenantUsage returns current quota config and usage for a tenant.
// GET /api/admin/tenant/{id}/quota  — superadmin only (PROJ-29).
// GET /api/admin/tenants/{id}/usage — superadmin only (PROJ-29, spec-conformant alias).
func (s *Server) handleGetTenantUsage(w http.ResponseWriter, r *http.Request) {
	tenantID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid tenant id")
		return
	}

	quota, err := s.tenantStore.GetQuota(r.Context(), tenantID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}

	usage, err := s.tenantStore.GetUsage(r.Context(), tenantID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}

	// Compute soft-limit warnings (≥80% = soft, ≥100% = hard).
	type warnings struct {
		StoragePct      *float64 `json:"storage_pct"`
		UsersPct        *float64 `json:"users_pct"`
		EmailsPct       *float64 `json:"emails_pct"`
		SoftLimitReached bool    `json:"soft_limit_reached"`
	}
	w80 := warnings{}
	softReached := false
	if quota.MaxStorageBytes != nil && *quota.MaxStorageBytes > 0 {
		pct := float64(usage.StorageBytes) / float64(*quota.MaxStorageBytes) * 100
		w80.StoragePct = &pct
		if pct >= 80 {
			softReached = true
		}
	}
	if quota.MaxUsers != nil && *quota.MaxUsers > 0 {
		pct := float64(usage.UserCount) / float64(*quota.MaxUsers) * 100
		w80.UsersPct = &pct
		if pct >= 80 {
			softReached = true
		}
	}
	if quota.MaxEmails != nil && *quota.MaxEmails > 0 {
		pct := float64(usage.EmailCount) / float64(*quota.MaxEmails) * 100
		w80.EmailsPct = &pct
		if pct >= 80 {
			softReached = true
		}
	}
	w80.SoftLimitReached = softReached

	writeJSON(w, http.StatusOK, map[string]interface{}{
		"storage_bytes": usage.StorageBytes,
		"user_count":    usage.UserCount,
		"email_count":   usage.EmailCount,
		"quotas": map[string]interface{}{
			"max_storage_bytes": quota.MaxStorageBytes,
			"max_users":         quota.MaxUsers,
			"max_emails":        quota.MaxEmails,
		},
		"warnings": w80,
	})
}

// handleSetTenantQuota sets quota limits for a tenant.
// PUT /api/admin/tenant/{id}/quota — superadmin only (PROJ-29).
func (s *Server) handleSetTenantQuota(w http.ResponseWriter, r *http.Request) {
	tenantID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid tenant id")
		return
	}

	var body tenantstore.TenantQuota
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, http.StatusBadRequest, "invalid body")
		return
	}

	if err := s.tenantStore.SetQuota(r.Context(), tenantID, body); err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}

	// Invalidate quota cache so the new limit takes effect immediately
	storage.InvalidateQuotaCache(tenantID)

	sess := sessionFromCtx(r.Context())
	if s.audlog != nil {
		s.audlog.Log(audit.Entry{
			EventType: "tenant_quota_changed",
			Username:  sess.Username,
			TenantID:  sess.TenantID,
			IPAddress: s.remoteIP(r),
			Success:   true,
			Detail:    fmt.Sprintf("tenant_id=%d", tenantID),
		})
	}

	writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true})
}

// handleGetAllTenantUsage returns quota and usage for all tenants.
// GET /api/admin/quotas — superadmin only (PROJ-29).
func (s *Server) handleGetAllTenantUsage(w http.ResponseWriter, r *http.Request) {
	tenants, err := s.tenantStore.List(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}

	type tenantWithUsage struct {
		ID              int64  `json:"id"`
		Name            string `json:"name"`
		Slug            string `json:"slug"`
		MaxStorageBytes *int64 `json:"max_storage_bytes"`
		MaxUsers        *int   `json:"max_users"`
		MaxEmails       *int64 `json:"max_emails"`
		StorageBytes    int64  `json:"storage_bytes"`
		UserCount       int64  `json:"user_count"`
		EmailCount      int64  `json:"email_count"`
	}

	result := make([]tenantWithUsage, 0, len(tenants))
	for _, t := range tenants {
		usage, err := s.tenantStore.GetUsage(r.Context(), t.ID)
		if err != nil {
			usage = &tenantstore.TenantUsage{}
		}
		result = append(result, tenantWithUsage{
			ID:              t.ID,
			Name:            t.Name,
			Slug:            t.Slug,
			MaxStorageBytes: t.MaxStorageBytes,
			MaxUsers:        t.MaxUsers,
			MaxEmails:       t.MaxEmails,
			StorageBytes:    usage.StorageBytes,
			UserCount:       usage.UserCount,
			EmailCount:      usage.EmailCount,
		})
	}

	writeJSON(w, http.StatusOK, map[string]interface{}{"tenants": result})
}
