// Supra Theme - Go Example
// This file demonstrates syntax highlighting for Go

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// User represents a user in our system
type User struct {
	ID        string    `json:"id" bson:"_id,omitempty"`
	Name      string    `json:"name" bson:"name"`
	Email     string    `json:"email" bson:"email"`
	Age       int       `json:"age" bson:"age"`
	IsActive  bool      `json:"is_active" bson:"is_active"`
	CreatedAt time.Time `json:"created_at" bson:"created_at"`
	UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
}

// UserService handles user-related operations
type UserService struct {
	collection *mongo.Collection
}

// NewUserService creates a new UserService instance
func NewUserService(collection *mongo.Collection) *UserService {
	return &UserService{
		collection: collection,
	}
}

// CreateUser creates a new user
func (us *UserService) CreateUser(ctx context.Context, user *User) error {
	user.CreatedAt = time.Now()
	user.UpdatedAt = time.Now()
	
	_, err := us.collection.InsertOne(ctx, user)
	if err != nil {
		return fmt.Errorf("failed to create user: %w", err)
	}
	
	return nil
}

// GetUserByID retrieves a user by ID
func (us *UserService) GetUserByID(ctx context.Context, id string) (*User, error) {
	var user User
	filter := bson.M{"_id": id}
	
	err := us.collection.FindOne(ctx, filter).Decode(&user)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, fmt.Errorf("user not found")
		}
		return nil, fmt.Errorf("failed to get user: %w", err)
	}
	
	return &user, nil
}

// ListUsers retrieves all users with pagination
func (us *UserService) ListUsers(ctx context.Context, limit, offset int) ([]*User, error) {
	var users []*User
	
	opts := options.Find().
		SetLimit(int64(limit)).
		SetSkip(int64(offset)).
		SetSort(bson.D{{Key: "created_at", Value: -1}})
	
	cursor, err := us.collection.Find(ctx, bson.M{}, opts)
	if err != nil {
		return nil, fmt.Errorf("failed to list users: %w", err)
	}
	defer cursor.Close(ctx)
	
	for cursor.Next(ctx) {
		var user User
		if err := cursor.Decode(&user); err != nil {
			return nil, fmt.Errorf("failed to decode user: %w", err)
		}
		users = append(users, &user)
	}
	
	if err := cursor.Err(); err != nil {
		return nil, fmt.Errorf("cursor error: %w", err)
	}
	
	return users, nil
}

// UpdateUser updates an existing user
func (us *UserService) UpdateUser(ctx context.Context, id string, updates map[string]interface{}) error {
	updates["updated_at"] = time.Now()
	
	filter := bson.M{"_id": id}
	update := bson.M{"$set": updates}
	
	result, err := us.collection.UpdateOne(ctx, filter, update)
	if err != nil {
		return fmt.Errorf("failed to update user: %w", err)
	}
	
	if result.MatchedCount == 0 {
		return fmt.Errorf("user not found")
	}
	
	return nil
}

// DeleteUser deletes a user by ID
func (us *UserService) DeleteUser(ctx context.Context, id string) error {
	filter := bson.M{"_id": id}
	
	result, err := us.collection.DeleteOne(ctx, filter)
	if err != nil {
		return fmt.Errorf("failed to delete user: %w", err)
	}
	
	if result.DeletedCount == 0 {
		return fmt.Errorf("user not found")
	}
	
	return nil
}

// HTTP handlers
type UserHandler struct {
	userService *UserService
}

// NewUserHandler creates a new UserHandler
func NewUserHandler(userService *UserService) *UserHandler {
	return &UserHandler{
		userService: userService,
	}
}

// CreateUserHandler handles POST /users
func (uh *UserHandler) CreateUserHandler(c *gin.Context) {
	var user User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	if user.Name == "" || user.Email == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "name and email are required"})
		return
	}
	
	if err := uh.userService.CreateUser(c.Request.Context(), &user); err != nil {
		log.Printf("Error creating user: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"})
		return
	}
	
	c.JSON(http.StatusCreated, gin.H{"message": "user created successfully", "user": user})
}

// GetUserHandler handles GET /users/:id
func (uh *UserHandler) GetUserHandler(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "user ID is required"})
		return
	}
	
	user, err := uh.userService.GetUserByID(c.Request.Context(), id)
	if err != nil {
		if err.Error() == "user not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
			return
		}
		log.Printf("Error getting user: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get user"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"user": user})
}

// ListUsersHandler handles GET /users
func (uh *UserHandler) ListUsersHandler(c *gin.Context) {
	limitStr := c.DefaultQuery("limit", "10")
	offsetStr := c.DefaultQuery("offset", "0")
	
	limit, err := strconv.Atoi(limitStr)
	if err != nil || limit <= 0 {
		limit = 10
	}
	
	offset, err := strconv.Atoi(offsetStr)
	if err != nil || offset < 0 {
		offset = 0
	}
	
	users, err := uh.userService.ListUsers(c.Request.Context(), limit, offset)
	if err != nil {
		log.Printf("Error listing users: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list users"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{
		"users": users,
		"limit": limit,
		"offset": offset,
		"count": len(users),
	})
}

// UpdateUserHandler handles PUT /users/:id
func (uh *UserHandler) UpdateUserHandler(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "user ID is required"})
		return
	}
	
	var updates map[string]interface{}
	if err := c.ShouldBindJSON(&updates); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	
	// Remove fields that shouldn't be updated
	delete(updates, "id")
	delete(updates, "created_at")
	
	if err := uh.userService.UpdateUser(c.Request.Context(), id, updates); err != nil {
		if err.Error() == "user not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
			return
		}
		log.Printf("Error updating user: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update user"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "user updated successfully"})
}

// DeleteUserHandler handles DELETE /users/:id
func (uh *UserHandler) DeleteUserHandler(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "user ID is required"})
		return
	}
	
	if err := uh.userService.DeleteUser(c.Request.Context(), id); err != nil {
		if err.Error() == "user not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
			return
		}
		log.Printf("Error deleting user: %v", err)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete user"})
		return
	}
	
	c.JSON(http.StatusOK, gin.H{"message": "user deleted successfully"})
}

// Database connection
func connectToMongoDB(uri string) (*mongo.Client, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	
	client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
	if err != nil {
		return nil, fmt.Errorf("failed to connect to MongoDB: %w", err)
	}
	
	// Test the connection
	if err := client.Ping(ctx, nil); err != nil {
		return nil, fmt.Errorf("failed to ping MongoDB: %w", err)
	}
	
	return client, nil
}

// Setup routes
func setupRoutes(r *gin.Engine, userHandler *UserHandler) {
	api := r.Group("/api/v1")
	{
		users := api.Group("/users")
		{
			users.POST("", userHandler.CreateUserHandler)
			users.GET("", userHandler.ListUsersHandler)
			users.GET("/:id", userHandler.GetUserHandler)
			users.PUT("/:id", userHandler.UpdateUserHandler)
			users.DELETE("/:id", userHandler.DeleteUserHandler)
		}
	}
}

// Main function
func main() {
	// Configuration
	mongoURI := "mongodb://localhost:27017"
	dbName := "supra_db"
	port := ":8080"
	
	// Connect to MongoDB
	client, err := connectToMongoDB(mongoURI)
	if err != nil {
		log.Fatalf("Failed to connect to MongoDB: %v", err)
	}
	defer func() {
		if err := client.Disconnect(context.Background()); err != nil {
			log.Printf("Error disconnecting from MongoDB: %v", err)
		}
	}()
	
	// Get database and collection
	db := client.Database(dbName)
	userCollection := db.Collection("users")
	
	// Initialize services
	userService := NewUserService(userCollection)
	userHandler := NewUserHandler(userService)
	
	// Setup Gin router
	r := gin.Default()
	
	// Add middleware
	r.Use(gin.Logger())
	r.Use(gin.Recovery())
	r.Use(func(c *gin.Context) {
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
		
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}
		
		c.Next()
	})
	
	// Setup routes
	setupRoutes(r, userHandler)
	
	// Health check endpoint
	r.GET("/health", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status": "healthy",
			"timestamp": time.Now().Unix(),
			"version": "1.0.0",
		})
	})
	
	// Start server
	log.Printf("Starting server on port %s", port)
	if err := r.Run(port); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}

// Example usage and testing functions
func ExampleUsage() {
	// This function demonstrates various Go features
	
	// Variables and constants
	const (
		MaxUsers = 1000
		DefaultLimit = 10
	)
	
	var (
		userCount int
		isRunning bool = true
		serverName string = "supra-api"
	)
	
	// Slices and maps
	users := []string{"alice", "bob", "charlie"}
	userAges := map[string]int{
		"alice": 25,
		"bob": 30,
		"charlie": 35,
	}
	
	// Loops
	for i := 0; i < len(users); i++ {
		fmt.Printf("User %d: %s\n", i+1, users[i])
	}
	
	for name, age := range userAges {
		fmt.Printf("%s is %d years old\n", name, age)
	}
	
	// Switch statement
	switch userCount {
	case 0:
		fmt.Println("No users found")
	case 1:
		fmt.Println("One user found")
	default:
		fmt.Printf("%d users found\n", userCount)
	}
	
	// Interface usage
	var writer interface{} = os.Stdout
	if w, ok := writer.(io.Writer); ok {
		w.Write([]byte("Hello from interface!\n"))
	}
	
	// Goroutine example
	go func() {
		time.Sleep(1 * time.Second)
		fmt.Println("Goroutine completed")
	}()
	
	// Channel example
	ch := make(chan string, 1)
	go func() {
		ch <- "Hello from channel!"
	}()
	
	select {
	case msg := <-ch:
		fmt.Println(msg)
	case <-time.After(2 * time.Second):
		fmt.Println("Timeout!")
	}
}

// Additional imports for the example
import (
	"io"
	"os"
)
