package webui

import (
	"net/http"
	"strings"
	"time"

	"mailgoserver/internal/db"
)

func emailDomain(addr string) string {
	if i := strings.LastIndex(addr, "@"); i >= 0 {
		return strings.ToLower(addr[i+1:])
	}
	return ""
}

// dashboard mirrors dashboard.py's dashboard(), scoped to the current admin's
// assigned domains unless they're a global admin.
func (a *App) dashboard(w http.ResponseWriter, r *http.Request) {
	scope := scopeFromContext(r)
	allowedNames, isGlobal, err := a.accessibleDomainNames(r)
	if err != nil {
		a.Logger.Error("dashboard: %v", err)
	}

	// Domain/sender/mailbox/DKIM counts are injected uniformly into every page by
	// render() (see computeNavCounts) — only "near quota" is dashboard-specific,
	// so it's the only mailbox stat still computed here.
	var mailboxesNearQuota int
	mailboxes, _ := a.DB.ListMailboxes()
	for _, m := range mailboxes {
		if !m.IsActive || (!isGlobal && !scope.Allowed(m.DomainID)) {
			continue
		}
		if m.QuotaBytes > 0 && float64(m.UsedBytes)/float64(m.QuotaBytes)*100 >= 90 {
			mailboxesNearQuota++
		}
	}

	allEmails, err := a.DB.ListEmailLogsPage(0, 50)
	if err != nil {
		setFlash(w, "error", "Error loading recent activity")
	}
	var recentEmails []db.EmailLog
	for _, e := range allEmails {
		if isGlobal || allowedNames[emailDomain(e.MailFrom)] {
			recentEmails = append(recentEmails, e)
		}
		if len(recentEmails) == 10 {
			break
		}
	}

	allAuths, _ := a.DB.ListRecentAuthLogs(50)
	var recentAuths []db.AuthLog
	for _, au := range allAuths {
		if isGlobal || allowedNames[authLogDomain(au.Identifier)] {
			recentAuths = append(recentAuths, au)
		}
		if len(recentAuths) == 10 {
			break
		}
	}

	data := M{
		"active":               "dashboard",
		"mailboxes_near_quota": mailboxesNearQuota,
		"recent_emails":        recentEmails,
		"recent_auths":         recentAuths,
	}

	// Attack-count tiles: blacklist entries aren't attributable to a single domain
	// (see blacklist.go's doc comment), so this is global-admin-only, matching the
	// Blacklist page and sidebar section's own gating.
	if isGlobal {
		now := time.Now()
		since24h := now.Add(-24 * time.Hour)
		since7d := now.Add(-7 * 24 * time.Hour)
		data["failed_auth_24h"], _ = a.DB.CountFailedAuthSince(since24h)
		data["failed_auth_7d"], _ = a.DB.CountFailedAuthSince(since7d)
		data["blacklist_events_24h"], _ = a.DB.CountBlacklistEventsSince(since24h)
		data["blacklist_events_7d"], _ = a.DB.CountBlacklistEventsSince(since7d)
		var activeBlacklistCount int
		if entries, err := a.DB.ListBlacklist(); err == nil {
			for _, e := range entries {
				if e.ExpiresAt.After(now) {
					activeBlacklistCount++
				}
			}
		}
		data["active_blacklist_count"] = activeBlacklistCount
	}

	a.render(w, r, "dashboard.html", data)
}

// authLogDomain best-effort extracts a domain name from an AuthLog identifier, whose
// format varies by auth_type: a bare email ("sender"), "ip -> domain" (ip), or
// "sender@x -> target@y" (sender_validation). There's no domain_id column on this
// table (it predates admin scoping), so this is a text heuristic, not a foreign key.
func authLogDomain(identifier string) string {
	if idx := strings.LastIndex(identifier, "->"); idx >= 0 {
		return emailOrBareDomain(strings.TrimSpace(identifier[idx+2:]))
	}
	return emailOrBareDomain(identifier)
}

func emailOrBareDomain(s string) string {
	if strings.Contains(s, "@") {
		return emailDomain(s)
	}
	return strings.ToLower(s)
}
