package api

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

	"archivmail/internal/audit"
	"archivmail/internal/tenantstore"
	"archivmail/internal/userstore"
)

// ── Tenant handlers ──────────────────────────────────────────────────────────

func (s *Server) handleListTenants(w http.ResponseWriter, r *http.Request) {
	if s.tenantStore == nil {
		writeError(w, http.StatusServiceUnavailable, "tenant store not available")
		return
	}
	tenants, err := s.tenantStore.List(r.Context())
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to list tenants")
		return
	}
	writeJSON(w, http.StatusOK, tenants)
}

func (s *Server) handleCreateTenant(w http.ResponseWriter, r *http.Request) {
	if s.tenantStore == nil {
		writeError(w, http.StatusServiceUnavailable, "tenant store not available")
		return
	}
	var req struct {
		Name string `json:"name"`
		Slug string `json:"slug"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	if req.Name == "" || req.Slug == "" {
		writeError(w, http.StatusBadRequest, "name and slug are required")
		return
	}

	tenant, err := s.tenantStore.Create(r.Context(), req.Name, req.Slug)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to create tenant")
		return
	}

	// Create default users for the new tenant.
	type defaultUserCreds struct {
		Username string `json:"username"`
		Password string `json:"password"`
		Role     string `json:"role"`
	}
	type createTenantResponse struct {
		*tenantstore.Tenant
		DefaultUsers []defaultUserCreds `json:"default_users"`
	}

	resp := createTenantResponse{Tenant: tenant}
	for _, spec := range []struct {
		suffix string
		role   string
	}{
		{suffix: "admin", role: userstore.RoleDomainAdmin},
		{suffix: "auditor", role: userstore.RoleAuditor},
	} {
		pw, pwErr := tenantRandomPassword()
		if pwErr != nil {
			writeError(w, http.StatusInternalServerError, "failed to generate password")
			return
		}
		username := req.Slug + "-" + spec.suffix
		email := fmt.Sprintf("%s@%s.local", username, req.Slug)
		u, uErr := s.users.Create(userstore.CreateUserRequest{
			Username: username,
			Email:    email,
			Password: pw,
			Role:     spec.role,
			TenantID: &tenant.ID,
		})
		if uErr != nil {
			writeError(w, http.StatusInternalServerError, "failed to create default user")
			return
		}
		resp.DefaultUsers = append(resp.DefaultUsers, defaultUserCreds{
			Username: u.Username,
			Password: pw,
			Role:     spec.role,
		})
	}

	sess := sessionFromCtx(r.Context())
	s.audlog.Log(audit.Entry{
		EventType: "tenant_created",
		Username:  sess.Username,
		TenantID:  sess.TenantID,
		IPAddress: s.remoteIP(r),
		Success:   true,
		Detail:    "Mandant erstellt: " + req.Name,
	})

	writeJSON(w, http.StatusCreated, resp)
}

func (s *Server) handleGetTenant(w http.ResponseWriter, r *http.Request) {
	if s.tenantStore == nil {
		writeError(w, http.StatusServiceUnavailable, "tenant store not available")
		return
	}
	id, err := parseTenantID(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid tenant id")
		return
	}
	// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
	if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}
	tenant, err := s.tenantStore.Get(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, "tenant not found")
		return
	}
	writeJSON(w, http.StatusOK, tenant)
}

func (s *Server) handleUpdateTenant(w http.ResponseWriter, r *http.Request) {
	if s.tenantStore == nil {
		writeError(w, http.StatusServiceUnavailable, "tenant store not available")
		return
	}
	id, err := parseTenantID(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid tenant id")
		return
	}

	// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
	if !tenantAccessAllowed(sessionFromCtx(r.Context()), &id) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}

	var req struct {
		Name   string `json:"name"`
		Active *bool  `json:"active"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	// Load existing to keep unset fields
	existing, err := s.tenantStore.Get(r.Context(), id)
	if err != nil {
		writeError(w, http.StatusNotFound, "tenant not found")
		return
	}
	name := existing.Name
	active := existing.Active
	if req.Name != "" {
		name = req.Name
	}
	if req.Active != nil {
		active = *req.Active
	}

	tenant, err := s.tenantStore.Update(r.Context(), id, name, active)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to update tenant")
		return
	}

	writeJSON(w, http.StatusOK, tenant)
}

func (s *Server) handleDeleteTenant(w http.ResponseWriter, r *http.Request) {
	if s.tenantStore == nil {
		writeError(w, http.StatusServiceUnavailable, "tenant store not available")
		return
	}
	id, err := parseTenantID(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid tenant id")
		return
	}

	sess := sessionFromCtx(r.Context())
	// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
	if !tenantAccessAllowed(sess, &id) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}
	if err := s.tenantStore.Delete(r.Context(), id); err != nil {
		writeError(w, http.StatusInternalServerError, "failed to delete tenant")
		return
	}

	s.audlog.Log(audit.Entry{
		EventType: "tenant_deleted",
		Username:  sess.Username,
		TenantID:  sess.TenantID,
		IPAddress: s.remoteIP(r),
		Success:   true,
		Detail:    "Mandant gelöscht: " + strconv.FormatInt(id, 10),
	})

	w.WriteHeader(http.StatusNoContent)
}

func (s *Server) handleListTenantUsers(w http.ResponseWriter, r *http.Request) {
	tenantID, err := parseTenantID(r)
	if err != nil {
		writeError(w, http.StatusBadRequest, "invalid tenant id")
		return
	}
	// Defense-in-depth tenant scope check (PROJ-63): no-op for global admins.
	if !tenantAccessAllowed(sessionFromCtx(r.Context()), &tenantID) {
		writeError(w, http.StatusForbidden, "access denied")
		return
	}
	users, err := s.users.ListByTenant(r.Context(), tenantID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "failed to list tenant users")
		return
	}
	if users == nil {
		users = []*userstore.User{}
	}
	writeJSON(w, http.StatusOK, users)
}
