package handlers

// gdpr.go — v0.34.0 CS2
//
// GDPR delete endpoint: DELETE /api/v1/me
// Allows a user to delete their own account and all associated data.

import (
	"crypto/sha256"
	"fmt"
	"log/slog"
	"net/http"

	"github.com/gin-gonic/gin"
	"golang.org/x/crypto/bcrypt"

	"chat-switchboard/models"
	"chat-switchboard/store"
)

// GDPRHandler serves account deletion endpoints.
type GDPRHandler struct {
	stores store.Stores
}

// NewGDPRHandler creates a new handler for GDPR operations.
func NewGDPRHandler(s store.Stores) *GDPRHandler {
	return &GDPRHandler{stores: s}
}

// deleteAccountRequest is the body for DELETE /api/v1/me.
type deleteAccountRequest struct {
	Confirm  string `json:"confirm"`
	Password string `json:"password"`
}

// DeleteMyAccount permanently deletes the requesting user's account.
// DELETE /api/v1/me
func (h *GDPRHandler) DeleteMyAccount(c *gin.Context) {
	ctx := c.Request.Context()
	userID := c.GetString("user_id")

	var req deleteAccountRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
		return
	}

	// Require explicit confirmation
	if req.Confirm != "DELETE" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "confirm field must be \"DELETE\""})
		return
	}

	// Fetch user
	user, err := h.stores.Users.GetByID(ctx, userID)
	if err != nil || user == nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
		return
	}

	// Verify password
	if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)); err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid password"})
		return
	}

	// Prevent deleting last admin
	if user.Role == "admin" {
		adminCount, err := h.stores.Export.CountActiveAdmins(ctx)
		if err != nil {
			slog.Error("gdpr: count admins", "error", err)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check admin count"})
			return
		}
		if adminCount <= 1 {
			c.JSON(http.StatusForbidden, gin.H{"error": "cannot delete the last admin account"})
			return
		}
	}

	// Generate anonymized hash from user ID
	hash := sha256.Sum256([]byte(userID))
	anonHash := fmt.Sprintf("%x", hash[:6]) // 12 hex chars

	// Step 1: Soft-delete/hard-delete user data
	counts, err := h.stores.Export.SoftDeleteUserData(ctx, userID)
	if err != nil {
		slog.Error("gdpr: delete user data", "error", err, "user_id", userID)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete user data"})
		return
	}

	// Step 2: Revoke tokens
	if err := h.stores.Export.DeleteUserTokens(ctx, userID); err != nil {
		slog.Error("gdpr: delete tokens", "error", err, "user_id", userID)
		// Continue — tokens will expire naturally
	}

	// Step 3: Delete personal provider configs
	if deleted, err := h.stores.Providers.DeletePersonalByOwner(ctx, userID); err != nil {
		slog.Error("gdpr: delete provider configs", "error", err)
	} else {
		counts["provider_configs"] = deleted
	}

	// Step 4: Anonymize user record
	if err := h.stores.Export.AnonymizeUser(ctx, userID, anonHash); err != nil {
		slog.Error("gdpr: anonymize user", "error", err, "user_id", userID)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to anonymize user"})
		return
	}

	// Audit log (before the user record is fully anonymized)
	anonUsername := "deleted-user-" + anonHash
	h.stores.Audit.Log(ctx, &models.AuditEntry{
		ActorID:      &userID,
		Action:       "user.gdpr_delete",
		ResourceType: "user",
		ResourceID:   userID,
		Metadata:     models.JSONMap{"anonymized_as": anonUsername, "deleted_counts": counts},
	})

	slog.Info("gdpr: account deleted", "user_id", userID, "anonymized_as", anonUsername)

	c.JSON(http.StatusOK, gin.H{
		"message":       "account deleted",
		"anonymized_as": anonUsername,
	})
}
