// Package rujukan handles Search BPJS services
// Generated on: 2025-09-07 11:01:18
package handlers

import (
	"context"
	"encoding/json"
	"net/http"
    "strings"
	"time"

	"api-service/internal/config"
	"api-service/internal/models"
	"api-service/internal/models/vclaim/rujukan"
	"api-service/internal/services/bpjs"
	"api-service/pkg/logger"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/google/uuid"
)
// SearchHandler handles Search BPJS services
type SearchHandler struct {
	service   services.VClaimService
	validator *validator.Validate
	logger    logger.Logger
	config    config.BpjsConfig
}
// SearchHandlerConfig contains configuration for SearchHandler
type SearchHandlerConfig struct {
	BpjsConfig config.BpjsConfig
	Logger     logger.Logger
	Validator  *validator.Validate
}
// NewSearchHandler creates a new SearchHandler
func NewSearchHandler(cfg SearchHandlerConfig) *SearchHandler {
	return &SearchHandler{
		service:   services.NewService(cfg.BpjsConfig),
		validator: cfg.Validator,
		logger:    cfg.Logger,
		config:    cfg.BpjsConfig,
	}
}


// GetBynorujukan godoc
// @Summary      Get Bynorujukan data
// @Description  Get rujukan by nomor rujukan
// @Tags         Rujukan
// @Accept       json
// @Produce      json 
// @Security     ApiKeyAuth 
// @Param        X-Request-ID    header    string                          false  "Request ID for tracking" 
// @Param        norujukan           path      string                          true   "norujukan" example("example_value") 
// @Success      200             {object}  rujukan.RujukanResponse "Successfully retrieved Bynorujukan data"
// @Failure      400             {object}  models.ErrorResponseBpjs        "Bad request - invalid parameters"
// @Failure      401             {object}  models.ErrorResponseBpjs        "Unauthorized - invalid API credentials"
// @Failure      404             {object}  models.ErrorResponseBpjs        "Not found - Bynorujukan not found"
// @Failure      500             {object}  models.ErrorResponseBpjs        "Internal server error"
// @Router       /bynorujukan/:norujukan [get]
func (h *SearchHandler) GetBynorujukan(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), 30*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)
    }

    
    h.logger.Info("Processing GetBynorujukan request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "/Rujukan/:norujukan",
        
        "norujukan": c.Param("norujukan"),
        
    })
    

    // Extract path parameters
    
    norujukan := c.Param("norujukan")
    if norujukan == "" {
        
        h.logger.Error("Missing required parameter norujukan", map[string]interface{}{
            "request_id": requestID,
        })
        
        c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
            Status:    "error",
            Message:   "Missing required parameter norujukan",
            RequestID: requestID,
        })
        return
    }
    

    // Call service method
    var response rujukan.RujukanResponse
    
    endpoint := "/Rujukan/:norujukan"
    
    endpoint = strings.Replace(endpoint, ":norujukan", norujukan, 1)
    
    resp, err := h.service.GetRawResponse(ctx, endpoint)
    
    if err != nil {
        
        h.logger.Error("Failed to get Bynorujukan", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        
        c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
            Status:    "error",
            Message:   "Internal server error",
            RequestID: requestID,
        })
        return
    }

    // Map the raw response
    response.MetaData = resp.MetaData
    if resp.Response != nil {
        response.Data = &rujukan.RujukanData{}
        if respStr, ok := resp.Response.(string); ok {
            // Decrypt the response string
            consID, secretKey, _, tstamp, _ := h.config.SetHeader()
            decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
            if err != nil {
                
                h.logger.Error("Failed to decrypt response", map[string]interface{}{
                    "error":      err.Error(),
                    "request_id": requestID,
                })
                
            } else {
                json.Unmarshal([]byte(decryptedResp), response.Data)
            }
        } else if respMap, ok := resp.Response.(map[string]interface{}); ok {
            // Response is already unmarshaled JSON
            if dataMap, exists := respMap["rujukan"]; exists {
                dataBytes, _ := json.Marshal(dataMap)
                json.Unmarshal(dataBytes, response.Data)
            } else {
                // Try to unmarshal the whole response
                respBytes, _ := json.Marshal(resp.Response)
                json.Unmarshal(respBytes, response.Data)
            }
        }
    }

    // Ensure response has proper fields
    response.Status = "success"
    response.RequestID = requestID
    c.JSON(http.StatusOK, response)
}










// GetBynokartu godoc
// @Summary      Get Bynokartu data
// @Description  Get rujukan by card number
// @Tags         Rujukan
// @Accept       json
// @Produce      json 
// @Security     ApiKeyAuth 
// @Param        X-Request-ID    header    string                          false  "Request ID for tracking" 
// @Param        nokartu           path      string                          true   "nokartu" example("example_value") 
// @Success      200             {object}  rujukan.RujukanResponse "Successfully retrieved Bynokartu data"
// @Failure      400             {object}  models.ErrorResponseBpjs        "Bad request - invalid parameters"
// @Failure      401             {object}  models.ErrorResponseBpjs        "Unauthorized - invalid API credentials"
// @Failure      404             {object}  models.ErrorResponseBpjs        "Not found - Bynokartu not found"
// @Failure      500             {object}  models.ErrorResponseBpjs        "Internal server error"
// @Router       /bynokartu/:nokartu [get]
func (h *SearchHandler) GetBynokartu(c *gin.Context) {
    ctx, cancel := context.WithTimeout(c.Request.Context(), 30*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)
    }

    
    h.logger.Info("Processing GetBynokartu request", map[string]interface{}{
        "request_id": requestID,
        "endpoint":   "/Rujukan/:nokartu",
        
        "nokartu": c.Param("nokartu"),
        
    })
    

    // Extract path parameters
    
    nokartu := c.Param("nokartu")
    if nokartu == "" {
        
        h.logger.Error("Missing required parameter nokartu", map[string]interface{}{
            "request_id": requestID,
        })
        
        c.JSON(http.StatusBadRequest, models.ErrorResponseBpjs{
            Status:    "error",
            Message:   "Missing required parameter nokartu",
            RequestID: requestID,
        })
        return
    }
    

    // Call service method
    var response rujukan.RujukanResponse
    
    endpoint := "/Rujukan/:nokartu"
    
    endpoint = strings.Replace(endpoint, ":nokartu", nokartu, 1)
    
    resp, err := h.service.GetRawResponse(ctx, endpoint)
    
    if err != nil {
        
        h.logger.Error("Failed to get Bynokartu", map[string]interface{}{
            "error":      err.Error(),
            "request_id": requestID,
        })
        
        c.JSON(http.StatusInternalServerError, models.ErrorResponseBpjs{
            Status:    "error",
            Message:   "Internal server error",
            RequestID: requestID,
        })
        return
    }

    // Map the raw response
    response.MetaData = resp.MetaData
    if resp.Response != nil {
        response.Data = &rujukan.RujukanData{}
        if respStr, ok := resp.Response.(string); ok {
            // Decrypt the response string
            consID, secretKey, _, tstamp, _ := h.config.SetHeader()
            decryptedResp, err := services.ResponseVclaim(respStr, consID+secretKey+tstamp)
            if err != nil {
                
                h.logger.Error("Failed to decrypt response", map[string]interface{}{
                    "error":      err.Error(),
                    "request_id": requestID,
                })
                
            } else {
                json.Unmarshal([]byte(decryptedResp), response.Data)
            }
        } else if respMap, ok := resp.Response.(map[string]interface{}); ok {
            // Response is already unmarshaled JSON
            if dataMap, exists := respMap["rujukan"]; exists {
                dataBytes, _ := json.Marshal(dataMap)
                json.Unmarshal(dataBytes, response.Data)
            } else {
                // Try to unmarshal the whole response
                respBytes, _ := json.Marshal(resp.Response)
                json.Unmarshal(respBytes, response.Data)
            }
        }
    }

    // Ensure response has proper fields
    response.Status = "success"
    response.RequestID = requestID
    c.JSON(http.StatusOK, response)
}








