package api

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

	"archivmail/internal/audit"
	"archivmail/internal/mailer"
	"archivmail/internal/tokenstore"
	"archivmail/internal/userstore"
)

// handleCreateInvite generates an invite token for a tenant and optionally emails it.
// POST /api/admin/invite  — domain_admin+  (PROJ-28)
func (s *Server) handleCreateInvite(w http.ResponseWriter, r *http.Request) {
	var body struct {
		TenantID int64  `json:"tenant_id"` // superadmin: arbitrary; domain_admin: own tenant
		Email    string `json:"email"`     // optional: send invite by email
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, http.StatusBadRequest, "invalid body")
		return
	}

	sess := sessionFromCtx(r.Context())

	// domain_admin may only invite to their own tenant
	if sess.Role != userstore.RoleSuperAdmin {
		tenantID := tenantFromCtx(r.Context())
		if tenantID == nil || *tenantID != body.TenantID {
			writeError(w, http.StatusForbidden, "forbidden")
			return
		}
	}

	tid := body.TenantID
	token, err := s.tokenStore.Create(r.Context(), tokenstore.TypeInvite, nil, &tid, 72*time.Hour)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err.Error())
		return
	}

	inviteURL := ""
	if s.fqdn != "" {
		inviteURL = "https://" + s.fqdn + "/signup?invite=" + token
	}

	// Optionally send invite email
	if body.Email != "" && s.mailer.IsConfigured() {
		tenantName := strconv.FormatInt(body.TenantID, 10)
		if s.tenantStore != nil {
			if t, err := s.tenantStore.Get(r.Context(), body.TenantID); err == nil {
				tenantName = t.Name
			}
		}
		go func() {
			html := mailer.InviteHTML(s.fqdn, token, tenantName)
			txt := mailer.InviteText(s.fqdn, token, tenantName)
			_ = s.mailer.Send(body.Email, "Einladung zu archivmail", html, txt)
		}()
	}

	if s.audlog != nil {
		s.audlog.Log(audit.Entry{
			EventType: "invite_created",
			Username:  sess.Username,
			TenantID:  sess.TenantID,
			IPAddress: s.remoteIP(r),
			Success:   true,
		})
	}

	writeJSON(w, http.StatusOK, map[string]interface{}{
		"token":      token,
		"invite_url": inviteURL,
	})
}

// handleCheckInvite validates an invite token and returns the tenant name.
// GET /api/auth/invite?token=...  (PROJ-28)
func (s *Server) handleCheckInvite(w http.ResponseWriter, r *http.Request) {
	plain := r.URL.Query().Get("token")
	if plain == "" {
		writeError(w, http.StatusBadRequest, "token required")
		return
	}

	tok, err := s.tokenStore.Peek(r.Context(), tokenstore.TypeInvite, plain)
	if err != nil {
		writeError(w, http.StatusBadRequest, "ungültiger oder abgelaufener Einladungslink")
		return
	}

	tenantName := ""
	if tok.TenantID != nil && s.tenantStore != nil {
		if t, err := s.tenantStore.Get(r.Context(), *tok.TenantID); err == nil {
			tenantName = t.Name
		}
	}

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