package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"text/template"
	"time"

	"gopkg.in/yaml.v2"
)

// ================== STRUCTURES FOR SEPARATION OF CONCERNS ==================
// HandlerValidation tracks validation and generation status with thread safety
type HandlerValidation struct {
	ExistingFunctions map[string]bool
	NewFunctions      []string
	UpdatedFiles      []string
	CreatedFiles      []string
	mu                sync.Mutex // For thread-safe access to slices
}

// DirectoryInfo represents directory structure for nested endpoints
type DirectoryInfo struct {
	Path      string
	IsFile    bool
	Functions []FunctionInfo
	Children  map[string]*DirectoryInfo
}

// FunctionInfo contains information about a function
type FunctionInfo struct {
	Name     string
	Methods  []string
	Endpoint string
	Config   EndpointConfig
}

// EndpointConfig contains configuration for an endpoint
type EndpointConfig struct {
	Methods       []string `yaml:"methods"`
	GetPath       string   `yaml:"get_path"`
	PostPath      string   `yaml:"post_path"`
	PutPath       string   `yaml:"put_path"`
	PatchPath     string   `yaml:"patch_path"`
	DeletePath    string   `yaml:"delete_path"`
	SearchPath    string   `yaml:"search_path"`
	Model         string   `yaml:"model"`
	ResponseModel string   `yaml:"response_model"`
	RequestModel  string   `yaml:"request_model"`
	Description   string   `yaml:"description"`
	Summary       string   `yaml:"summary"`
	Tags          []string `yaml:"tags"`
	RequireAuth   bool     `yaml:"require_auth"`
	CacheEnabled  bool     `yaml:"cache_enabled"`
	CacheTTL      int      `yaml:"cache_ttl"`
	FhirProfiles  []string `yaml:"fhir_profiles"`
	SearchParams  []string `yaml:"search_params"`
}

// GlobalConfig contains global configuration
type GlobalConfig struct {
	ModuleName    string `yaml:"module_name"`
	OutputDir     string `yaml:"output_dir"`
	EnableSwagger bool   `yaml:"enable_swagger"`
	EnableLogging bool   `yaml:"enable_logging"`
	EnableMetrics bool   `yaml:"enable_metrics"`
	EnableAuth    bool   `yaml:"enable_auth"`
	BaseURL       string `yaml:"base_url"`
	Version       string `yaml:"version"`
	Environment   string `yaml:"environment"`
	FhirVersion   string `yaml:"fhir_version"`
	ProfileURL    string `yaml:"profile_url"`
}

// ServiceConfig contains complete service configuration
type ServiceConfig struct {
	Global   GlobalConfig       `yaml:"global,omitempty"`
	Services map[string]Service `yaml:"services"`
}

// Service represents a single service
type Service struct {
	Name         string                   `yaml:"name"`
	Category     string                   `yaml:"category"`
	Package      string                   `yaml:"package"`
	Description  string                   `yaml:"description"`
	BaseURL      string                   `yaml:"base_url"`
	Timeout      int                      `yaml:"timeout"`
	RetryCount   int                      `yaml:"retry_count"`
	FhirResource string                   `yaml:"fhir_resource,omitempty"`
	Validation   ValidationConfig         `yaml:"validation,omitempty"`
	Auth         AuthConfig               `yaml:"authentication,omitempty"`
	Endpoints    map[string]EndpointGroup `yaml:"endpoints"`
	Dependencies string                   `yaml:"dependencies,omitempty"`
	Middleware   string                   `yaml:"middleware,omitempty"`
}

// ValidationConfig contains validation rules
type ValidationConfig struct {
	EnableFhirValidation bool     `yaml:"enable_fhir_validation"`
	RequiredFields       []string `yaml:"required_fields"`
	CustomValidators     []string `yaml:"custom_validators"`
}

// AuthConfig contains authentication configuration
type AuthConfig struct {
	Type     string   `yaml:"type"`
	TokenURL string   `yaml:"token_url"`
	Scopes   []string `yaml:"scopes"`
}

// EndpointGroup represents a group of related endpoints - MODIFIED to match your YAML
type EndpointGroup struct {
	Description string                 `yaml:"description"`
	Basic       map[string]interface{} `yaml:"basic"`
	// Generated fields
	HandlerFolder string
	HandlerFile   string
	HandlerName   string
	Functions     map[string]FunctionConfig
}

// FunctionConfig contains individual function configuration
type FunctionConfig struct {
	Methods    []string `yaml:"methods"`
	Path       string   `yaml:"path"`
	Model      string   `yaml:"model"`
	RoutesLink string   `yaml:"routes_link"`
	// Path for swagger documentation
	GetPath       string   `yaml:"get_path"`
	PostPath      string   `yaml:"post_path"`
	PutPath       string   `yaml:"put_path"`
	PatchPath     string   `yaml:"patch_path"`
	DeletePath    string   `yaml:"delete_path"`
	SearchPath    string   `yaml:"search_path"`
	ResponseModel string   `yaml:"response_model"`
	RequestModel  string   `yaml:"request_model"`
	Description   string   `yaml:"description"`
	Summary       string   `yaml:"summary"`
	Tags          []string `yaml:"tags"`
	RequireAuth   bool     `yaml:"require_auth"`
	CacheEnabled  bool     `yaml:"cache_enabled"`
	CacheTTL      int      `yaml:"cache_ttl"`
	FhirProfiles  []string `yaml:"fhir_profiles"`
	SearchParams  []string `yaml:"search_params"`
}

// TemplateData contains data for template generation
type TemplateData struct {
	ServiceName               string
	ServiceLower              string
	ServiceUpper              string
	Category                  string
	CategoryParts             []string
	Package                   string
	Description               string
	BaseURL                   string
	Timeout                   int
	RetryCount                int
	FhirResource              string
	Endpoints                 []EndpointData
	Timestamp                 string
	ModuleName                string
	HasValidator              bool
	HasLogger                 bool
	HasSwagger                bool
	GlobalConfig              GlobalConfig
	ShouldGenerateStruct      bool
	ShouldGenerateConstructor bool
	FunctionalArea            string
	HandlerName               string
	DirectoryDepth            int
}

// EndpointData contains endpoint-specific data
type EndpointData struct {
	Name          string
	NameLower     string
	NameUpper     string
	NameCamel     string
	Methods       []string
	GetPath       string
	PostPath      string
	PutPath       string
	PatchPath     string
	DeletePath    string
	SearchPath    string
	Model         string
	ResponseModel string
	RequestModel  string
	DataModel     string
	Description   string
	Summary       string
	Tags          []string
	HasGet        bool
	HasPost       bool
	HasPut        bool
	HasPatch      bool
	HasDelete     bool
	HasSearch     bool
	RequireAuth   bool
	CacheEnabled  bool
	CacheTTL      int
	PathParams    []string
	ModelPackage  string
	FhirResource  string
	CategoryPath  string
}

// ================== MAIN GENERATION FUNCTIONS ==================
// generateHandlerWithValidation generates handler with separation of concerns
func generateHandlerWithValidation(
	ctx context.Context,
	serviceName string,
	svc Service,
	gc GlobalConfig,
) error {
	validation := &HandlerValidation{
		ExistingFunctions: make(map[string]bool),
		NewFunctions:      []string{},
		UpdatedFiles:      []string{},
		CreatedFiles:      []string{},
	}

	baseDir := gc.OutputDir
	var wg sync.WaitGroup
	errChan := make(chan error, len(svc.Endpoints))

	// Debug: Print service information
	fmt.Printf("🔍 Debug: Processing service %s with %d endpoints\n", serviceName, len(svc.Endpoints))

	// Process each endpoint group concurrently
	for groupName, grp := range svc.Endpoints {
		wg.Add(1)
		go func(groupName string, grp EndpointGroup) {
			defer wg.Done()
			select {
			case <-ctx.Done():
				errChan <- ctx.Err()
				return
			default:
				// Debug: Print endpoint group information
				fmt.Printf("🔍 Debug: Processing endpoint group %s with %d functions\n", groupName, len(grp.Functions))

				// Create handler folder structure
				categoryParts := strings.Split(svc.Category, "/")
				handlerDirParts := append([]string{baseDir}, categoryParts...)
				handlerDir := filepath.Join(handlerDirParts...)
				if err := os.MkdirAll(handlerDir, 0755); err != nil {
					errChan <- fmt.Errorf("mkdir %s: %w", handlerDir, err)
					return
				}

				// Generate methods file with clear naming
				methodsFileName := fmt.Sprintf("%s.go", strings.ToLower(svc.Package))
				methodsFilePath := filepath.Join(handlerDir, methodsFileName)

				// Check if methods file exists
				fileExists := false
				if _, err := os.Stat(methodsFilePath); err == nil {
					fileExists = true
				}

				if !fileExists {
					// Create new methods file
					err := createMethodsFileFromConfig(
						methodsFilePath, svc, grp, gc, groupName,
					)
					if err != nil {
						errChan <- fmt.Errorf("create methods file %s: %w", methodsFilePath, err)
						return
					}
					validation.mu.Lock()
					validation.CreatedFiles = append(validation.CreatedFiles, methodsFilePath)
					validation.mu.Unlock()
					fmt.Printf("✅ Created methods file: %s\n", methodsFilePath)
				} else {
					// Update existing methods file with new functions only
					err := updateExistingMethodsFile(
						methodsFilePath, svc, grp, gc, groupName, validation,
					)
					if err != nil {
						errChan <- fmt.Errorf("update methods file %s: %w", methodsFilePath, err)
						return
					}
					validation.mu.Lock()
					if len(validation.NewFunctions) > 0 {
						validation.UpdatedFiles = append(validation.UpdatedFiles, methodsFilePath)
					}
					validation.mu.Unlock()
					fmt.Printf("✅ Updated methods file: %s\n", methodsFilePath)
				}
			}
		}(groupName, grp)
	}

	// Wait for all goroutines to complete
	wg.Wait()
	close(errChan)

	// Check for errors
	for err := range errChan {
		if err != nil {
			return err
		}
	}

	// Generate models (sequential for simplicity)
	if err := generateModels(ctx, svc, gc); err != nil {
		return fmt.Errorf("generate models: %w", err)
	}

	// Generate routes
	if err := generateRoutes(serviceName, svc, gc); err != nil {
		return fmt.Errorf("generate routes: %w", err)
	}

	return nil
}

// createMethodsFileFromConfig creates new methods file from configuration
func createMethodsFileFromConfig(
	filePath string,
	svc Service,
	grp EndpointGroup,
	gc GlobalConfig,
	functionalArea string,
) error {
	// Debug: Print function information
	fmt.Printf("🔍 Debug: Creating methods file with %d functions\n", len(grp.Functions))
	for funcName, funcConfig := range grp.Functions {
		fmt.Printf("🔍 Debug: Function %s has methods: %v\n", funcName, funcConfig.Methods)
	}

	// Collect all functions for this group
	var allEndpoints []EndpointData
	for fname, fcfg := range grp.Functions {
		td := processFunctionData(svc, grp, fname, fcfg, gc)
		allEndpoints = append(allEndpoints, td.Endpoints...)
	}

	templateData := TemplateData{
		ServiceName:               svc.Name,
		ServiceLower:              strings.ToLower(svc.Name),
		ServiceUpper:              strings.ToUpper(svc.Name),
		Category:                  svc.Category,
		CategoryParts:             strings.Split(svc.Category, "/"),
		Package:                   svc.Package,
		Description:               svc.Description,
		BaseURL:                   svc.BaseURL,
		Timeout:                   svc.Timeout,
		RetryCount:                svc.RetryCount,
		FhirResource:              svc.FhirResource,
		Endpoints:                 allEndpoints,
		Timestamp:                 time.Now().Format("2006-01-02 15:04:05"),
		ModuleName:                gc.ModuleName,
		HasValidator:              true,
		HasLogger:                 gc.EnableLogging,
		HasSwagger:                gc.EnableSwagger,
		GlobalConfig:              gc,
		ShouldGenerateStruct:      false, // NEVER generate struct in methods file
		ShouldGenerateConstructor: false, // NEVER generate constructor in methods file
		FunctionalArea:            functionalArea,
		HandlerName:               grp.HandlerName,
		DirectoryDepth:            len(strings.Split(svc.Category, "/")),
	}

	return createMethodsFile(filePath, templateData)
}

// updateExistingMethodsFile updates existing methods file with new functions
func updateExistingMethodsFile(
	filePath string,
	svc Service,
	grp EndpointGroup,
	gc GlobalConfig,
	functionalArea string,
	validation *HandlerValidation,
) error {
	existingContent, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}
	content := string(existingContent)

	// Debug: Print function information
	fmt.Printf("🔍 Debug: Updating methods file with %d functions\n", len(grp.Functions))
	for funcName, funcConfig := range grp.Functions {
		fmt.Printf("🔍 Debug: Function %s has methods: %v\n", funcName, funcConfig.Methods)
	}

	// Check for existing functions and collect new ones
	var newEndpoints []EndpointData
	for fname, fcfg := range grp.Functions {
		functionExists := false
		for _, method := range fcfg.Methods {
			funcName := generateFunctionName(fname, method)
			sig := fmt.Sprintf("func (h *%sHandler) %s", grp.HandlerName, funcName)
			if strings.Contains(content, sig) {
				fmt.Printf("⚠️ Skip existing: %s (%s)\n", fname, funcName)
				functionExists = true
				break
			}
		}
		if functionExists {
			continue
		}

		td := processFunctionData(svc, grp, fname, fcfg, gc)
		newEndpoints = append(newEndpoints, td.Endpoints...)
		validation.mu.Lock()
		validation.NewFunctions = append(validation.NewFunctions, fname)
		validation.mu.Unlock()
		fmt.Printf("✅ Will add: %s\n", fname)
	}

	if len(newEndpoints) == 0 {
		fmt.Printf("⏭️ No new functions to add\n")
		return nil
	}

	// Generate new functions using methods-only template
	templateData := TemplateData{
		ServiceName:               svc.Name,
		ServiceLower:              strings.ToLower(svc.Name),
		ServiceUpper:              strings.ToUpper(svc.Name),
		Category:                  svc.Category,
		CategoryParts:             strings.Split(svc.Category, "/"),
		Package:                   svc.Package,
		Description:               svc.Description,
		BaseURL:                   svc.BaseURL,
		Timeout:                   svc.Timeout,
		RetryCount:                svc.RetryCount,
		FhirResource:              svc.FhirResource,
		Endpoints:                 newEndpoints,
		Timestamp:                 time.Now().Format("2006-01-02 15:04:05"),
		ModuleName:                gc.ModuleName,
		HasValidator:              true,
		HasLogger:                 gc.EnableLogging,
		HasSwagger:                gc.EnableSwagger,
		GlobalConfig:              gc,
		ShouldGenerateStruct:      false, // NEVER
		ShouldGenerateConstructor: false, // NEVER
		FunctionalArea:            functionalArea,
		HandlerName:               grp.HandlerName,
		DirectoryDepth:            len(strings.Split(svc.Category, "/")),
	}

	newFunctions, err := generateNewMethodsOnly(templateData)
	if err != nil {
		return err
	}

	// Merge content
	mergedContent := mergeGoFileContent(content, newFunctions)
	return ioutil.WriteFile(filePath, []byte(mergedContent), 0644)
}

// processFunctionData processes individual function configuration
func processFunctionData(
	svc Service,
	grp EndpointGroup,
	fname string,
	fcfg FunctionConfig,
	gc GlobalConfig,
) TemplateData {
	fmt.Printf("🔍 Debug: Processing function %s with methods: %v\n", fname, fcfg.Methods)

	ed := EndpointData{
		Name:          toCamelCase(fname),
		NameLower:     strings.ToLower(fname),
		NameUpper:     strings.ToUpper(fname),
		NameCamel:     toCamelCase(fname),
		Methods:       fcfg.Methods,
		GetPath:       fcfg.GetPath,
		PostPath:      fcfg.PostPath,
		PutPath:       fcfg.PutPath,
		PatchPath:     fcfg.PatchPath,
		DeletePath:    fcfg.DeletePath,
		SearchPath:    fcfg.SearchPath,
		Model:         fcfg.Model,
		ResponseModel: fcfg.ResponseModel,
		RequestModel:  fcfg.Model,
		DataModel:     strings.Replace(fcfg.ResponseModel, "Response", "Data", 1),
		Description:   fcfg.Description,
		Summary:       fcfg.Summary,
		Tags:          fcfg.Tags,
		RequireAuth:   fcfg.RequireAuth,
		CacheEnabled:  fcfg.CacheEnabled,
		CacheTTL:      fcfg.CacheTTL,
		PathParams:    extractPathParams(fcfg.GetPath),
		ModelPackage:  svc.Package,
		FhirResource:  svc.FhirResource,
		CategoryPath:  svc.Category,
	}

	// Set method flags
	for _, m := range fcfg.Methods {
		switch strings.ToUpper(m) {
		case "GET":
			ed.HasGet = true
		case "POST":
			ed.HasPost = true
		case "PUT":
			ed.HasPut = true
		case "PATCH":
			ed.HasPatch = true
		case "DELETE":
			ed.HasDelete = true
		case "SEARCH":
			ed.HasSearch = true
		}
	}

	fmt.Printf("🔍 Debug: Function %s flags - Get:%t, Post:%t, Put:%t, Patch:%t, Delete:%t, Search:%t\n",
		fname, ed.HasGet, ed.HasPost, ed.HasPut, ed.HasPatch, ed.HasDelete, ed.HasSearch)

	return TemplateData{
		ServiceName:    svc.Name,
		ServiceLower:   strings.ToLower(svc.Name),
		ServiceUpper:   strings.ToUpper(svc.Name),
		Category:       svc.Category,
		CategoryParts:  strings.Split(svc.Category, "/"),
		Package:        svc.Package,
		Description:    svc.Description,
		BaseURL:        svc.BaseURL,
		Timeout:        svc.Timeout,
		RetryCount:     svc.RetryCount,
		FhirResource:   svc.FhirResource,
		Endpoints:      []EndpointData{ed},
		Timestamp:      time.Now().Format("2006-01-02 15:04:05"),
		ModuleName:     gc.ModuleName,
		HasValidator:   true,
		HasLogger:      gc.EnableLogging,
		HasSwagger:     gc.EnableSwagger,
		GlobalConfig:   gc,
		HandlerName:    grp.HandlerName,
		DirectoryDepth: len(strings.Split(svc.Category, "/")),
	}
}

// generateModels generates model files for the service
func generateModels(ctx context.Context, svc Service, gc GlobalConfig) error {
	// Create model directory structure
	categoryParts := strings.Split(svc.Category, "/")
	modelDirParts := append([]string{"internal", "models"}, categoryParts...)
	modelDir := filepath.Join(modelDirParts...)
	if err := os.MkdirAll(modelDir, 0755); err != nil {
		return fmt.Errorf("mkdir %s: %w", modelDir, err)
	}

	modelFilePath := filepath.Join(modelDir, strings.ToLower(svc.Package)+".go")

	// Check if model file exists
	if _, err := os.Stat(modelFilePath); err == nil {
		fmt.Printf("⏭️ Model file already exists: %s\n", modelFilePath)
		return nil
	}

	// Check if context was cancelled
	select {
	case <-ctx.Done():
		return ctx.Err()
	default:
	}

	// Generate model content
	templateData := TemplateData{
		ServiceName:    svc.Name,
		ServiceLower:   strings.ToLower(svc.Name),
		ServiceUpper:   strings.ToUpper(svc.Name),
		Category:       svc.Category,
		CategoryParts:  categoryParts,
		Package:        svc.Package,
		FhirResource:   svc.FhirResource,
		Timestamp:      time.Now().Format("2006-01-02 15:04:05"),
		ModuleName:     gc.ModuleName,
		DirectoryDepth: len(categoryParts),
	}

	tmpl := template.New("model")
	tmpl, err := tmpl.Parse(modelTemplate)
	if err != nil {
		return err
	}

	file, err := os.Create(modelFilePath)
	if err != nil {
		return err
	}
	defer file.Close()

	err = tmpl.Execute(file, templateData)
	if err != nil {
		return err
	}

	fmt.Printf("✅ Created model file: %s\n", modelFilePath)
	return nil
}

// generateRoutes generates routes for the service
func generateRoutes(serviceName string, svc Service, gc GlobalConfig) error {
	routesFilePath := filepath.Join(gc.OutputDir, "routes.go")
	if _, err := os.Stat(routesFilePath); os.IsNotExist(err) {
		// Create routes file if it doesn't exist
		if err := os.MkdirAll(filepath.Dir(routesFilePath), 0755); err != nil {
			return fmt.Errorf("mkdir %s: %w", filepath.Dir(routesFilePath), err)
		}

		// Create a basic routes file
		routesContent := fmt.Sprintf(`package handlers
import (
    "%s/internal/config"
    "%s/pkg/logger"
    "github.com/gin-gonic/gin"
    "github.com/go-playground/validator/v10"
)

// SetupRoutes sets up all routes for the application
func SetupRoutes(r *gin.Engine, cfg *config.Config) error {
    // Setup routes will be added here
    return nil
}
`, gc.ModuleName, gc.ModuleName)

		if err := ioutil.WriteFile(routesFilePath, []byte(routesContent), 0644); err != nil {
			return fmt.Errorf("create routes file: %w", err)
		}
		fmt.Printf("✅ Created routes file: %s\n", routesFilePath)
	}

	routesContent, err := ioutil.ReadFile(routesFilePath)
	if err != nil {
		return fmt.Errorf("read routes file: %w", err)
	}
	routesContentStr := string(routesContent)

	// Check if routes are already registered
	if strings.Contains(routesContentStr, fmt.Sprintf("Register%sRoutes", svc.Name)) {
		fmt.Printf("⚠️ Routes for %s already registered\n", svc.Name)
		return nil
	}

	var imports []string
	var allRoutes []string

	// Track handler folders that have been imported
	processedFolders := make(map[string]bool)

	for groupName, grp := range svc.Endpoints {
		// Import based on handler folder
		if !processedFolders[grp.HandlerFolder] {
			importLine := fmt.Sprintf("\t%sHandlers \"%s/internal/handlers/%s\"",
				grp.HandlerFolder, gc.ModuleName, grp.HandlerFolder)
			imports = append(imports, importLine)
			processedFolders[grp.HandlerFolder] = true
			fmt.Printf("✅ Added import: %sHandlers\n", grp.HandlerFolder)
		}

		var routesCode strings.Builder

		// Use groupName for comment and identifier
		routesCode.WriteString(fmt.Sprintf("\n\t// %s (%s) routes\n", grp.Description, groupName))

		// Handler instantiation using HandlerName from config
		routesCode.WriteString(fmt.Sprintf("\t%sHandler := %sHandlers.New%sHandler(%sHandlers.%sHandlerConfig{\n",
			strings.ToLower(grp.HandlerName),
			grp.HandlerFolder,
			grp.HandlerName,
			grp.HandlerFolder,
			grp.HandlerName))
		routesCode.WriteString("\t\tConfig: cfg,\n")
		routesCode.WriteString("\t\tLogger: logger.Default(),\n")
		routesCode.WriteString("\t\tValidator: validator.New(),\n")
		routesCode.WriteString("\t})\n")

		// Use groupName for route group path
		routesCode.WriteString(fmt.Sprintf("\t%sGroup := r.Group(\"/%s\")\n",
			strings.ToLower(grp.HandlerName), groupName))

		// Process functions
		for fname, fcfg := range grp.Functions {
			td := processFunctionData(svc, grp, fname, fcfg, gc)
			for _, endpoint := range td.Endpoints {
				handlerVar := strings.ToLower(grp.HandlerName) + "Handler"
				groupVar := strings.ToLower(grp.HandlerName) + "Group"

				// Loop through methods and use specific routes
				for _, method := range fcfg.Methods {
					var cleanPath string

					// Choose path based on method
					switch strings.ToUpper(method) {
					case "GET":
						cleanPath = fcfg.GetPath
					case "POST":
						cleanPath = fcfg.PostPath
					case "PUT":
						cleanPath = fcfg.PutPath
					case "PATCH":
						cleanPath = fcfg.PatchPath
					case "DELETE":
						cleanPath = fcfg.DeletePath
					case "SEARCH":
						cleanPath = fcfg.SearchPath
					default:
						fmt.Printf("⚠️ Unsupported HTTP method: %s for function %s\n", method, fname)
						continue
					}

					// Fallback to path if specific route is empty
					if cleanPath == "" {
						cleanPath = fcfg.Path
					}

					// Clean path - remove groupName prefix if exists
					if strings.HasPrefix(cleanPath, "/"+groupName) {
						cleanPath = strings.TrimPrefix(cleanPath, "/"+groupName)
					}
					if cleanPath == "" {
						cleanPath = "/"
					}

					// Generate route based on method
					switch strings.ToUpper(method) {
					case "GET":
						routesCode.WriteString(fmt.Sprintf("\t%s.GET(\"%s\", %s.Get%s)\n",
							groupVar, cleanPath, handlerVar, endpoint.Name))
					case "POST":
						routesCode.WriteString(fmt.Sprintf("\t%s.POST(\"%s\", %s.Create%s)\n",
							groupVar, cleanPath, handlerVar, endpoint.Name))
					case "PUT":
						routesCode.WriteString(fmt.Sprintf("\t%s.PUT(\"%s\", %s.Update%s)\n",
							groupVar, cleanPath, handlerVar, endpoint.Name))
					case "PATCH":
						routesCode.WriteString(fmt.Sprintf("\t%s.PATCH(\"%s\", %s.Patch%s)\n",
							groupVar, cleanPath, handlerVar, endpoint.Name))
					case "DELETE":
						routesCode.WriteString(fmt.Sprintf("\t%s.DELETE(\"%s\", %s.Delete%s)\n",
							groupVar, cleanPath, handlerVar, endpoint.Name))
					case "SEARCH":
						routesCode.WriteString(fmt.Sprintf("\t%s.GET(\"%s\", %s.Search%s)\n",
							groupVar, cleanPath, handlerVar, endpoint.Name))
					}
				}
			}
		}

		allRoutes = append(allRoutes, routesCode.String())
	}

	// Insert imports after existing imports
	if len(imports) > 0 {
		importSection := strings.Join(imports, "\n") + "\n"
		// Find position after import section
		importMarker := "import ("
		if strings.Contains(routesContentStr, importMarker) {
			importIndex := strings.Index(routesContentStr, importMarker)
			closingParenIndex := strings.Index(routesContentStr[importIndex:], "\n)") + importIndex
			if closingParenIndex > importIndex {
				routesContentStr = routesContentStr[:closingParenIndex+2] + "\n" + importSection + routesContentStr[closingParenIndex+2:]
			}
		}
	}

	// Find and insert routes
	setupRoutesMarker := "func SetupRoutes"
	if !strings.Contains(routesContentStr, setupRoutesMarker) {
		return fmt.Errorf("SetupRoutes function not found in routes.go")
	}

	funcStart := strings.Index(routesContentStr, setupRoutesMarker)
	funcBodyStart := strings.Index(routesContentStr[funcStart:], "{") + funcStart + 1
	newRoutesContent := routesContentStr[:funcBodyStart+1] + "\n" + strings.Join(allRoutes, "\n") + "\n" + routesContentStr[funcBodyStart+1:]

	err = ioutil.WriteFile(routesFilePath, []byte(newRoutesContent), 0644)
	if err != nil {
		return fmt.Errorf("write updated routes file: %w", err)
	}

	fmt.Printf("✅ Updated routes file with %s routes\n", svc.Name)
	return nil
}

// ================== HELPER FUNCTIONS ==================
// generateFunctionName generates function name based on endpoint and method
func generateFunctionName(endpointName, method string) string {
	switch strings.ToUpper(method) {
	case "GET":
		return fmt.Sprintf("Get%s", strings.Title(endpointName))
	case "POST":
		return fmt.Sprintf("Create%s", strings.Title(endpointName))
	case "PUT":
		return fmt.Sprintf("Update%s", strings.Title(endpointName))
	case "DELETE":
		return fmt.Sprintf("Delete%s", strings.Title(endpointName))
	case "PATCH":
		return fmt.Sprintf("Patch%s", strings.Title(endpointName))
	case "SEARCH":
		return fmt.Sprintf("Search%s", strings.Title(endpointName))
	default:
		return fmt.Sprintf("%s%s", strings.Title(method), strings.Title(endpointName))
	}
}

// extractPathParams extracts path parameters from URL path
func extractPathParams(path string) []string {
	var params []string
	for _, part := range strings.Split(path, "/") {
		if strings.HasPrefix(part, ":") {
			params = append(params, strings.TrimPrefix(part, ":"))
		}
	}
	return params
}

// toCamelCase converts string to CamelCase
func toCamelCase(s string) string {
	parts := strings.FieldsFunc(s, func(r rune) bool {
		return r == '_' || r == '-' || r == ' '
	})
	for i, p := range parts {
		parts[i] = strings.Title(strings.ToLower(p))
	}
	return strings.Join(parts, "")
}

// createMethodsFile creates methods file using template
func createMethodsFile(filePath string, templateData TemplateData) error {
	if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
		return err
	}

	// Debug: Print template data
	fmt.Printf("🔍 Debug: Creating methods file with %d endpoints\n", len(templateData.Endpoints))
	for _, endpoint := range templateData.Endpoints {
		fmt.Printf("🔍 Debug: Endpoint %s has methods: %v\n", endpoint.Name, endpoint.Methods)
	}

	// Create template with basic functions
	tmpl := template.New("methods").Funcs(template.FuncMap{
		"title": strings.Title,
		"upper": strings.ToUpper,
		"lower": strings.ToLower,
		"index": func(slice []string, i int) string {
			if i >= 0 && i < len(slice) {
				return slice[i]
			}
			return ""
		},
		"add": func(a, b int) int {
			return a + b
		},
		"sub": func(a, b int) int {
			return a - b
		},
	})

	tmpl, err := tmpl.Parse(handlerTemplate)
	if err != nil {
		return fmt.Errorf("parse template: %w", err)
	}

	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	return tmpl.Execute(file, templateData)
}

// generateNewMethodsOnly generates only new methods for existing files
func generateNewMethodsOnly(templateData TemplateData) (string, error) {
	// Debug: Print template data
	fmt.Printf("🔍 Debug: Generating new methods with %d endpoints\n", len(templateData.Endpoints))
	for _, endpoint := range templateData.Endpoints {
		fmt.Printf("🔍 Debug: Endpoint %s has methods: %v\n", endpoint.Name, endpoint.Methods)
	}

	// Create template with basic functions only
	tmpl := template.New("newMethods").Funcs(template.FuncMap{
		"title": strings.Title,
		"upper": strings.ToUpper,
		"lower": strings.ToLower,
		"index": func(slice []string, i int) string {
			if i >= 0 && i < len(slice) {
				return slice[i]
			}
			return ""
		},
	})

	tmpl, err := tmpl.Parse(methodsOnlyTemplate)
	if err != nil {
		return "", err
	}

	var result strings.Builder
	err = tmpl.Execute(&result, templateData)
	if err != nil {
		return "", err
	}

	return result.String(), nil
}

// mergeGoFileContent merges new functions into existing file
func mergeGoFileContent(existingContent, newFunctions string) string {
	// Find last closing brace
	re := regexp.MustCompile(`}\s*$`)
	lastBraceIndex := re.FindStringIndex(existingContent)
	if lastBraceIndex == nil {
		return existingContent + "\n" + newFunctions
	}

	before := existingContent[:lastBraceIndex[0]]
	after := existingContent[lastBraceIndex[0]:]

	return before + "\n" + newFunctions + "\n" + after
}

// ================== MAIN FUNCTION ==================
func main() {
	if len(os.Args) < 2 {
		printUsage()
		os.Exit(1)
	}

	configFile := os.Args[1]
	var targetService string
	if len(os.Args) > 2 {
		targetService = os.Args[2]
	}

	config, err := loadConfig(configFile)
	if err != nil {
		fmt.Printf("Error loading config: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("🚀 Starting Handler Generation with Validation...")
	fmt.Printf("📁 Config file: %s\n", configFile)
	if targetService != "" {
		fmt.Printf("🎯 Target service: %s\n", targetService)
	}

	// Create context with cancellation for graceful shutdown
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Worker pool for concurrent processing
	type result struct {
		serviceName string
		err         error
	}
	results := make(chan result)
	jobs := make(chan string, len(config.Services))

	// Start worker pool
	var wg sync.WaitGroup
	numWorkers := 4 // Adjust based on your system
	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for serviceName := range jobs {
				select {
				case <-ctx.Done():
					return
				case results <- result{
					serviceName: serviceName,
					err:         generateHandlerWithValidation(ctx, serviceName, config.Services[serviceName], config.Global),
				}:
				}
			}
		}()
	}

	// Send jobs to workers
	go func() {
		for serviceName := range config.Services {
			if targetService != "" && serviceName != targetService {
				continue
			}
			select {
			case <-ctx.Done():
				break
			case jobs <- serviceName:
			}
		}
		close(jobs)
	}()

	// Collect results
	go func() {
		wg.Wait()
		close(results)
	}()

	// Process results
	generated := 0
	errors := 0
	for res := range results {
		if res.err != nil {
			fmt.Printf("❌ Error generating handler for %s: %v\n", res.serviceName, res.err)
			errors++
			continue
		}
		generated++
	}

	// Summary
	fmt.Println("\n📊 Generation Summary:")
	fmt.Printf("✅ Successfully processed: %d services\n", generated)
	if errors > 0 {
		fmt.Printf("❌ Failed: %d services\n", errors)
	}
	if generated > 0 {
		fmt.Println("🎉 Generation completed successfully!")
	}
}

// loadConfig loads configuration from YAML file
func loadConfig(filename string) (*ServiceConfig, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	var config ServiceConfig
	err = yaml.Unmarshal(data, &config)
	if err != nil {
		return nil, err
	}

	// Set defaults
	if config.Global.ModuleName == "" {
		config.Global.ModuleName = "api-service"
	}
	if config.Global.OutputDir == "" {
		config.Global.OutputDir = "internal/handlers"
	}

	// Debug: Print loaded configuration
	fmt.Printf("🔍 Debug: Loaded %d services\n", len(config.Services))

	// Process endpoint groups to add missing handler information
	for serviceName, service := range config.Services {
		fmt.Printf("🔍 Debug: Processing service %s with %d endpoints\n", serviceName, len(service.Endpoints))

		for endpointName, endpointGroup := range service.Endpoints {
			fmt.Printf("🔍 Debug: Processing endpoint %s with %d basic configs\n", endpointName, len(endpointGroup.Basic))

			// Generate handler information based on service and endpoint names
			endpointGroup.HandlerFolder = strings.ToLower(service.Package)
			endpointGroup.HandlerFile = fmt.Sprintf("%s.go", strings.ToLower(service.Package))
			endpointGroup.HandlerName = toCamelCase(serviceName)

			// Convert basic map to functions map
			endpointGroup.Functions = make(map[string]FunctionConfig)

			// Debug: Print the structure of basic configs
			fmt.Printf("🔍 Debug: Processing basic config for endpoint %s\n", endpointName)

			// Treat the entire Basic map as a single function configuration
			funcConfig := FunctionConfig{}

			// Process each field in the basic config
			for key, value := range endpointGroup.Basic {
				keyStr := fmt.Sprintf("%v", key)
				processYAMLField(keyStr, value, &funcConfig)
			}

			fmt.Printf("🔍 Debug: Final function config for %s: methods=%v, get_path=%s\n",
				endpointName, funcConfig.Methods, funcConfig.GetPath)

			endpointGroup.Functions["basic"] = funcConfig

			// Update the service endpoints
			service.Endpoints[endpointName] = endpointGroup
		}
		config.Services[serviceName] = service
	}

	return &config, nil
}

// processYAMLField processes a single YAML field and updates the function config
func processYAMLField(key string, value interface{}, funcConfig *FunctionConfig) {
	fmt.Printf("🔍 Debug: Processing key %s with value %v (type: %T)\n", key, value, value)

	switch key {
	case "methods":
		if methods, ok := value.([]interface{}); ok {
			for _, method := range methods {
				if methodStr, ok := method.(string); ok {
					funcConfig.Methods = append(funcConfig.Methods, methodStr)
					fmt.Printf("🔍 Debug: Added method %s\n", methodStr)
				}
			}
		}
	case "get_path":
		if path, ok := value.(string); ok {
			funcConfig.GetPath = path
			fmt.Printf("🔍 Debug: Set get_path to %s\n", path)
		}
	case "post_path":
		if path, ok := value.(string); ok {
			funcConfig.PostPath = path
			fmt.Printf("🔍 Debug: Set post_path to %s\n", path)
		}
	case "put_path":
		if path, ok := value.(string); ok {
			funcConfig.PutPath = path
			fmt.Printf("🔍 Debug: Set put_path to %s\n", path)
		}
	case "patch_path":
		if path, ok := value.(string); ok {
			funcConfig.PatchPath = path
			fmt.Printf("🔍 Debug: Set patch_path to %s\n", path)
		}
	case "delete_path":
		if path, ok := value.(string); ok {
			funcConfig.DeletePath = path
			fmt.Printf("🔍 Debug: Set delete_path to %s\n", path)
		}
	case "search_path":
		if path, ok := value.(string); ok {
			funcConfig.SearchPath = path
			fmt.Printf("🔍 Debug: Set search_path to %s\n", path)
		}
	case "model":
		if model, ok := value.(string); ok {
			funcConfig.Model = model
			fmt.Printf("🔍 Debug: Set model to %s\n", model)
		}
	case "response_model":
		if model, ok := value.(string); ok {
			funcConfig.ResponseModel = model
			fmt.Printf("🔍 Debug: Set response_model to %s\n", model)
		}
	case "description":
		if desc, ok := value.(string); ok {
			funcConfig.Description = desc
			fmt.Printf("🔍 Debug: Set description to %s\n", desc)
		}
	case "summary":
		if summary, ok := value.(string); ok {
			funcConfig.Summary = summary
			fmt.Printf("🔍 Debug: Set summary to %s\n", summary)
		}
	case "tags":
		if tags, ok := value.([]interface{}); ok {
			for _, tag := range tags {
				if tagStr, ok := tag.(string); ok {
					funcConfig.Tags = append(funcConfig.Tags, tagStr)
					fmt.Printf("🔍 Debug: Added tag %s\n", tagStr)
				}
			}
		}
	case "require_auth":
		if auth, ok := value.(bool); ok {
			funcConfig.RequireAuth = auth
			fmt.Printf("🔍 Debug: Set require_auth to %t\n", auth)
		}
	case "cache_enabled":
		if cache, ok := value.(bool); ok {
			funcConfig.CacheEnabled = cache
			fmt.Printf("🔍 Debug: Set cache_enabled to %t\n", cache)
		}
	case "cache_ttl":
		if ttl, ok := value.(int); ok {
			funcConfig.CacheTTL = ttl
			fmt.Printf("🔍 Debug: Set cache_ttl to %d\n", ttl)
		}
	case "fhir_profiles":
		if profiles, ok := value.([]interface{}); ok {
			for _, profile := range profiles {
				if profileStr, ok := profile.(string); ok {
					funcConfig.FhirProfiles = append(funcConfig.FhirProfiles, profileStr)
					fmt.Printf("🔍 Debug: Added fhir_profile %s\n", profileStr)
				}
			}
		}
	case "search_params":
		if params, ok := value.([]interface{}); ok {
			for _, param := range params {
				if paramStr, ok := param.(string); ok {
					funcConfig.SearchParams = append(funcConfig.SearchParams, paramStr)
					fmt.Printf("🔍 Debug: Added search_param %s\n", paramStr)
				}
			}
		}
	default:
		fmt.Printf("⚠️ Debug: Unknown key %s\n", key)
	}
}

// printUsage prints usage information
func printUsage() {
	fmt.Println("Satu Sehat FHIR Handler Generator")
	fmt.Println()
	fmt.Println("Usage:")
	fmt.Println("  go run generate-satusehat-handler.go <config-file> [service-name]")
	fmt.Println()
	fmt.Println("Examples:")
	fmt.Println("  go run generate-satusehat-handler.go services-config-satusehat.yaml")
	fmt.Println("  go run generate-satusehat-handler.go services-config-satusehat.yaml patient")
}

// ================== TEMPLATES ==================
const handlerTemplate = `// Package {{.Package}} handles {{.HandlerName}} services
// Generated on: {{.Timestamp}}
package {{.Package}}

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"
    "strings"
    "time"
    "{{.ModuleName}}/internal/config"
    "{{.ModuleName}}/internal/models/{{.Package}}"
    "{{.ModuleName}}/pkg/logger"
    "github.com/gin-gonic/gin"
    "github.com/go-playground/validator/v10"
    "github.com/google/uuid"
)

// {{.HandlerName}} handles {{.HandlerName}} services
type {{.HandlerName}} struct {
    service   interface{}
    validator *validator.Validate
    logger    logger.Logger
    config    *config.Config
}

// {{.HandlerName}}Config contains configuration for {{.HandlerName}}
type {{.HandlerName}}Config struct {
    Config    *config.Config
    Logger    logger.Logger
    Validator *validator.Validate
}

// New{{.HandlerName}} creates a new {{.HandlerName}}
func New{{.HandlerName}}(cfg {{.HandlerName}}Config) *{{.HandlerName}} {
    return &{{.HandlerName}}{
        service:   nil, // Initialize with appropriate service
        validator: cfg.Validator,
        logger:    cfg.Logger,
        config:    cfg.Config,
    }
}

{{range .Endpoints}}
{{if .HasPost}}
// Create{{.Name}} creates a new resource
// @Summary Create a new resource
// @Description Create a new resource in the system
// @Tags {{index .Tags 0}}
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param request body models.{{.Name}}CreateRequest true "Resource creation request"
// @Success 201 {object} models.{{.Name}}Response "Resource created successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router {{.PostPath}} [post]
func (h *{{$.HandlerName}}) Create{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Create{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.PostPath}}",
    })
    {{end}}
    
    // Bind and validate request body
    var req models.{{.Name}}CreateRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Failed to bind request body", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Invalid request body: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // Validate request structure
    if err := h.validator.Struct(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Request validation failed", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Validation failed: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // TODO: Implement service call
    // Example: resp, err := h.service.CreateResource(ctx, req)
    
    // For now, return a mock response
    response := models.{{.Name}}Response{
        Status:    "success",
        Message:   "{{.Name}} created successfully",
        RequestID: requestID,
        Data:      nil, // Replace with actual data
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully created {{.Name}}", map[string]interface{}{
        "request_id": requestID,
    })
    {{end}}
    
    c.JSON(http.StatusCreated, response)
}
{{end}}
{{if .HasGet}}
// Get{{.Name}} retrieves a specific resource by ID
// @Summary Get a specific resource by ID
// @Description Retrieve a specific resource from the system
// @Tags {{index .Tags 0}}
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param id path string true "Resource ID"
// @Success 200 {object} models.{{.Name}}Response "Resource retrieved successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 404 {object} models.ErrorResponse "Resource not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router {{.GetPath}} [get]
func (h *{{$.HandlerName}}) Get{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    id := c.Param("id")
    if id == "" {
        {{if $.HasLogger}}
        h.logger.Error("Missing required parameter id", map[string]interface{}{
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Missing required parameter id",
            RequestID: requestID,
        })
        return
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Get{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.GetPath}}",
        "id":         id,
    })
    {{end}}
    
    // TODO: Implement service call
    // Example: resp, err := h.service.GetResource(ctx, id)
    
    // For now, return a mock response
    response := models.{{.Name}}Response{
        Status:    "success",
        Message:   "{{.Name}} retrieved successfully",
        RequestID: requestID,
        Data:      nil, // Replace with actual data
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully retrieved {{.Name}}", map[string]interface{}{
        "request_id": requestID,
        "id":         id,
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{if .HasPut}}
// Update{{.Name}} updates an existing resource
// @Summary Update an existing resource
// @Description Update an existing resource in the system
// @Tags {{index .Tags 0}}
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param id path string true "Resource ID"
// @Param request body models.{{.Name}}UpdateRequest true "Resource update request"
// @Success 200 {object} models.{{.Name}}Response "Resource updated successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 404 {object} models.ErrorResponse "Resource not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router {{.PutPath}} [put]
func (h *{{$.HandlerName}}) Update{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    id := c.Param("id")
    if id == "" {
        {{if $.HasLogger}}
        h.logger.Error("Missing required parameter id", map[string]interface{}{
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Missing required parameter id",
            RequestID: requestID,
        })
        return
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Update{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.PutPath}}",
        "id":         id,
    })
    {{end}}
    
    // Bind and validate request body
    var req models.{{.Name}}UpdateRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Failed to bind request body", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Invalid request body: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // Validate request structure
    if err := h.validator.Struct(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Request validation failed", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Validation failed: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // TODO: Implement service call
    // Example: resp, err := h.service.UpdateResource(ctx, id, req)
    
    // For now, return a mock response
    response := models.{{.Name}}Response{
        Status:    "success",
        Message:   "{{.Name}} updated successfully",
        RequestID: requestID,
        Data:      nil, // Replace with actual data
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully updated {{.Name}}", map[string]interface{}{
        "request_id": requestID,
        "id":         id,
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{if .HasDelete}}
// Delete{{.Name}} deletes a resource
// @Summary Delete a resource
// @Description Delete a resource from the system
// @Tags {{index .Tags 0}}
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param id path string true "Resource ID"
// @Success 200 {object} models.SuccessResponse "Resource deleted successfully"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 404 {object} models.ErrorResponse "Resource not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router {{.DeletePath}} [delete]
func (h *{{$.HandlerName}}) Delete{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    id := c.Param("id")
    if id == "" {
        {{if $.HasLogger}}
        h.logger.Error("Missing required parameter id", map[string]interface{}{
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Missing required parameter id",
            RequestID: requestID,
        })
        return
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Delete{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.DeletePath}}",
        "id":         id,
    })
    {{end}}
    
    // TODO: Implement service call
    // Example: err := h.service.DeleteResource(ctx, id)
    
    // For now, return a mock response
    response := models.SuccessResponse{
        Status:    "success",
        Message:   "{{.Name}} deleted successfully",
        RequestID: requestID,
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully deleted {{.Name}}", map[string]interface{}{
        "request_id": requestID,
        "id":         id,
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{if .HasSearch}}
// Search{{.Name}} searches for resources
// @Summary Search for resources
// @Description Search for resources in the system
// @Tags {{index .Tags 0}}
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param query query string false "Search query"
// @Param limit query int false "Limit results" default(10)
// @Param offset query int false "Offset results" default(0)
// @Success 200 {object} models.{{.Name}}SearchResponse "Search results"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router {{.SearchPath}} [get]
func (h *{{$.HandlerName}}) Search{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    // Get query parameters
    query := c.Query("query")
    limit := 10
    if l := c.Query("limit"); l != "" {
        if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
            limit = parsed
        }
    }
    offset := 0
    if o := c.Query("offset"); o != "" {
        if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
            offset = parsed
        }
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Search{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.SearchPath}}",
        "query":      query,
        "limit":      limit,
        "offset":     offset,
    })
    {{end}}
    
    // TODO: Implement service call
    // Example: resp, err := h.service.SearchResources(ctx, query, limit, offset)
    
    // For now, return a mock response
    response := models.{{.Name}}SearchResponse{
        Status:    "success",
        Message:   "Search completed successfully",
        RequestID: requestID,
        Data: models.SearchData{
            Results: []interface{}{}, // Replace with actual results
            Total:   0,
            Limit:   limit,
            Offset:  offset,
        },
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully completed search", map[string]interface{}{
        "request_id": requestID,
        "query":      query,
        "results":    len(response.Data.Results),
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{end}}`

const methodsOnlyTemplate = `{{range .Endpoints}}
{{if .HasPost}}
// Create{{.Name}} creates a new resource
func (h *{{$.HandlerName}}) Create{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Create{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.PostPath}}",
    })
    {{end}}
    
    // Bind and validate request body
    var req models.{{.Name}}CreateRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Failed to bind request body", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Invalid request body: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // Validate request structure
    if err := h.validator.Struct(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Request validation failed", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Validation failed: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // TODO: Implement service call
    // Example: resp, err := h.service.CreateResource(ctx, req)
    // For now, return a mock response
    response := models.{{.Name}}Response{
        Status:    "success",
        Message:   "{{.Name}} created successfully",
        RequestID: requestID,
        Data:      nil, // Replace with actual data
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully created {{.Name}}", map[string]interface{}{
        "request_id": requestID,
    })
    {{end}}
    
    c.JSON(http.StatusCreated, response)
}
{{end}}
{{if .HasGet}}
// Get{{.Name}} retrieves a specific resource by ID
func (h *{{$.HandlerName}}) Get{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    id := c.Param("id")
    if id == "" {
        {{if $.HasLogger}}
        h.logger.Error("Missing required parameter id", map[string]interface{}{
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Missing required parameter id",
            RequestID: requestID,
        })
        return
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Get{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.GetPath}}",
        "id":         id,
    })
    {{end}}
    
    // TODO: Implement service call
    // Example: resp, err := h.service.GetResource(ctx, id)
    // For now, return a mock response
    response := models.{{.Name}}Response{
        Status:    "success",
        Message:   "{{.Name}} retrieved successfully",
        RequestID: requestID,
        Data:      nil, // Replace with actual data
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully retrieved {{.Name}}", map[string]interface{}{
        "request_id": requestID,
        "id":         id,
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{if .HasPut}}
// Update{{.Name}} updates an existing resource
func (h *{{$.HandlerName}}) Update{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    id := c.Param("id")
    if id == "" {
        {{if $.HasLogger}}
        h.logger.Error("Missing required parameter id", map[string]interface{}{
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Missing required parameter id",
            RequestID: requestID,
        })
        return
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Update{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.PutPath}}",
        "id":         id,
    })
    {{end}}
    
    // Bind and validate request body
    var req models.{{.Name}}UpdateRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Failed to bind request body", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Invalid request body: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // Validate request structure
    if err := h.validator.Struct(&req); err != nil {
        {{if $.HasLogger}}
        h.logger.Error("Request validation failed", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Validation failed: " + err.Error(),
            RequestID: requestID,
        })
        return
    }
    
    // TODO: Implement service call
    // Example: resp, err := h.service.UpdateResource(ctx, id, req)
    // For now, return a mock response
    response := models.{{.Name}}Response{
        Status:    "success",
        Message:   "{{.Name}} updated successfully",
        RequestID: requestID,
        Data:      nil, // Replace with actual data
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully updated {{.Name}}", map[string]interface{}{
        "request_id": requestID,
        "id":         id,
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{if .HasDelete}}
// Delete{{.Name}} deletes a resource
func (h *{{$.HandlerName}}) Delete{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    id := c.Param("id")
    if id == "" {
        {{if $.HasLogger}}
        h.logger.Error("Missing required parameter id", map[string]interface{}{
            "request_id": requestID,
        })
        {{end}}
        c.JSON(http.StatusBadRequest, models.ErrorResponse{
            Status:    "error",
            Message:   "Missing required parameter id",
            RequestID: requestID,
        })
        return
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Delete{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.DeletePath}}",
        "id":         id,
    })
    {{end}}
    
    // TODO: Implement service call
    // Example: err := h.service.DeleteResource(ctx, id)
    // For now, return a mock response
    response := models.SuccessResponse{
        Status:    "success",
        Message:   "{{.Name}} deleted successfully",
        RequestID: requestID,
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully deleted {{.Name}}", map[string]interface{}{
        "request_id": requestID,
        "id":         id,
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{if .HasSearch}}
// Search{{.Name}} searches for resources
func (h *{{$.HandlerName}}) Search{{.Name}}(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
    defer cancel()
    
    // Generate request ID if not present
    requestID := c.GetHeader("X-Request-ID")
    if requestID == "" {
        requestID = uuid.New().String()
        c.Header("X-Request-ID", requestID)
    }
    
    // Get query parameters
    query := c.Query("query")
    limit := 10
    if l := c.Query("limit"); l != "" {
        if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
            limit = parsed
        }
    }
    offset := 0
    if o := c.Query("offset"); o != "" {
        if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
            offset = parsed
        }
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Processing Search{{.Name}} request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "{{.SearchPath}}",
        "query":      query,
        "limit":      limit,
        "offset":     offset,
    })
    {{end}}
    
    // TODO: Implement service call
    // Example: resp, err := h.service.SearchResources(ctx, query, limit, offset)
    // For now, return a mock response
    response := models.{{.Name}}SearchResponse{
        Status:    "success",
        Message:   "Search completed successfully",
        RequestID: requestID,
        Data: models.SearchData{
            Results: []interface{}{}, // Replace with actual results
            Total:   0,
            Limit:   limit,
            Offset:  offset,
        },
    }
    
    {{if $.HasLogger}}
    h.logger.Info("Successfully completed search", map[string]interface{}{
        "request_id": requestID,
        "query":      query,
        "results":    len(response.Data.Results),
    })
    {{end}}
    
    c.JSON(http.StatusOK, response)
}
{{end}}
{{end}}`

const modelTemplate = `package models

import (
    "time"
    "github.com/go-playground/validator/v10"
)

// BaseRequest contains common fields for all requests
type BaseRequest struct {
    RequestID string    ` + "`json:\"request_id,omitempty\"`" + `
    Timestamp time.Time ` + "`json:\"timestamp,omitempty\"`" + `
}

// BaseResponse contains common fields for all responses
type BaseResponse struct {
    Status    string      ` + "`json:\"status\"`" + `
    Message   string      ` + "`json:\"message\"`" + `
    Data      interface{} ` + "`json:\"data,omitempty\"`" + `
    RequestID string      ` + "`json:\"request_id,omitempty\"`" + `
}

// ErrorResponse represents an error response
type ErrorResponse struct {
    Status    string ` + "`json:\"status\"`" + `
    Message   string ` + "`json:\"message\"`" + `
    RequestID string ` + "`json:\"request_id,omitempty\"`" + `
}

// SuccessResponse represents a success response
type SuccessResponse struct {
    Status    string ` + "`json:\"status\"`" + `
    Message   string ` + "`json:\"message\"`" + `
    RequestID string ` + "`json:\"request_id,omitempty\"`" + `
}

// SearchData contains search results
type SearchData struct {
    Results []interface{} ` + "`json:\"results\"`" + `
    Total   int           ` + "`json:\"total\"`" + `
    Limit   int           ` + "`json:\"limit\"`" + `
    Offset  int           ` + "`json:\"offset\"`" + `
}

// {{.ServiceName}} Models
// Generated at: {{.Timestamp}}

// {{.ServiceName}}CreateRequest represents a request to create a {{.ServiceName}}
type {{.ServiceName}}CreateRequest struct {
    BaseRequest
    // Add fields specific to {{.ServiceName}} creation
    Name        string ` + "`json:\"name\" validate:\"required\"`" + `
    Description string ` + "`json:\"description\" validate:\"omitempty\"`" + `
}

// {{.ServiceName}}UpdateRequest represents a request to update a {{.ServiceName}}
type {{.ServiceName}}UpdateRequest struct {
    BaseRequest
    ID          string ` + "`json:\"id\" validate:\"required,uuid\"`" + `
    Name        string ` + "`json:\"name\" validate:\"required\"`" + `
    Description string ` + "`json:\"description\" validate:\"omitempty\"`" + `
}

// {{.ServiceName}}Response represents a response for {{.ServiceName}} operations
type {{.ServiceName}}Response struct {
    BaseResponse
}

// {{.ServiceName}}SearchResponse represents a response for {{.ServiceName}} search
type {{.ServiceName}}SearchResponse struct {
    BaseResponse
    Data SearchData ` + "`json:\"data\"`" + `
}

// {{.ServiceName}}Data represents the data structure for {{.ServiceName}}
type {{.ServiceName}}Data struct {
    ID          string    ` + "`json:\"id\"`" + `
    Name        string    ` + "`json:\"name\"`" + `
    Description string    ` + "`json:\"description,omitempty\"`" + `
    CreatedAt   time.Time ` + "`json:\"created_at\"`" + `
    UpdatedAt   time.Time ` + "`json:\"updated_at,omitempty\"`" + `
}

// Validate validates the {{.ServiceName}}CreateRequest
func (r *{{.ServiceName}}CreateRequest) Validate() error {
    validate := validator.New()
    return validate.Struct(r)
}

// Validate validates the {{.ServiceName}}UpdateRequest
func (r *{{.ServiceName}}UpdateRequest) Validate() error {
    validate := validator.New()
    return validate.Struct(r)
}

// New{{.ServiceName}}Data creates a new {{.ServiceName}}Data with default values
func New{{.ServiceName}}Data(name, description string) *{{.ServiceName}}Data {
    now := time.Now()
    return &{{.ServiceName}}Data{
        ID:          "", // Will be set by the database
        Name:        name,
        Description: description,
        CreatedAt:   now,
        UpdatedAt:   now,
    }
}`
