package main

import (
	"encoding/json"
	"fmt"
	"log"
)

// section: model
// User represents a database model with sensitive fields
type User struct {
	ID       int    `json:"id"`
	Name     string `json:"name"`
	Email    string `json:"email"`
	Password string `json:"password"` // Sensitive!
	APIKey   string `json:"api_key"`  // Sensitive!
}

// section: model

// section: viewmodel
// PublicUser is a view model that hides sensitive fields from API responses.
// Note: json:"-" on an embedded field does NOT work - the marshaler
// still digs into the embedded struct's fields.
type PublicUser struct {
	User
	Password string `json:"-"`        // Hide password
	APIKey   string `json:"api_key,omitempty"` // Hide if empty
}

// NewPublicUser creates a safe-to-serialize view of the user
func NewPublicUser(u User) PublicUser {
	return PublicUser{
		User:     u,
		Password: "", // Shadows User.Password, hidden by json:"-"
		APIKey:   "", // Shadows User.APIKey, omitted when empty
	}
}

// section: viewmodel

// section: main
func main() {
	// Simulate a user from the database
	dbUser := User{
		ID:       1,
		Name:     "Alice",
		Email:    "alice@example.com",
		Password: "super-secret-password",
		APIKey:   "sk-1234567890abcdef",
	}

	// BAD: Directly marshaling exposes sensitive data
	fmt.Println("Direct marshal (UNSAFE):")
	bad, _ := json.MarshalIndent(dbUser, "", "  ")
	fmt.Println(string(bad))

	// GOOD: Use view model to hide sensitive fields
	fmt.Println("\nView model marshal (SAFE):")
	publicUser := NewPublicUser(dbUser)
	good, err := json.MarshalIndent(publicUser, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(good))
}

// section: main

/* Output:
Direct marshal (UNSAFE):
{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com",
  "password": "super-secret-password",
  "api_key": "sk-1234567890abcdef"
}

View model marshal (SAFE):
{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com"
}
*/
