// Package patient handles Patient services
// Generated on: 2025-09-07 17:42:51
package patient

import (
	"api-service/internal/config"
	models "api-service/internal/models/patient"
	satusehat "api-service/internal/services/satusehat"
	"api-service/pkg/logger"
	"context"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/google/uuid"
)

// Patient handles Patient services
type Patient struct {
	satusehatService satusehat.SatuSehatService
	validator        *validator.Validate
	logger           logger.Logger
	config           *config.Config
}

// PatientConfig contains configuration for Patient
type PatientConfig struct {
	Config           *config.Config
	Logger           logger.Logger
	Validator        *validator.Validate
	SatusehatService satusehat.SatuSehatService
}

// NewPatient creates a new Patient
func NewPatient(cfg PatientConfig) *Patient {
	return &Patient{
		satusehatService: cfg.SatusehatService,
		validator:        cfg.Validator,
		logger:           cfg.Logger,
		config:           cfg.Config,
	}
}

// CreateBasic creates a new resource
// @Summary Create a new resource
// @Description Create a new resource in the system
// @Tags Patient
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param request body models.PatientCreateRequest true "Resource creation request"
// @Success 201 {object} models.PatientCreateRequest "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  [post]
func (h *Patient) CreateBasic(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 CreateBasic request", map[string]interface{}{
		"request_id": requestID,
		"endpoint":   "",
	})

	// Bind and validate request body
	var req models.PatientCreateRequest
	if err := c.ShouldBindJSON(&req); err != nil {

		h.logger.Error("Failed to bind request body", map[string]interface{}{
			"error":      err.Error(),
			"request_id": requestID,
		})

		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 {

		h.logger.Error("Request validation failed", map[string]interface{}{
			"error":      err.Error(),
			"request_id": requestID,
		})

		c.JSON(http.StatusBadRequest, models.ErrorResponse{
			Status:    "error",
			Message:   "Validation failed: " + err.Error(),
			RequestID: requestID,
		})
		return
	}

	// Call SATUSEHAT service to create patient
	resp := h.satusehatService.Post(ctx, "/Patient", req, &models.PatientResponse{})

	response := models.PatientResponse{
		BaseResponse: models.BaseResponse{
			Status:    "success",
			Message:   "Patient created successfully",
			RequestID: requestID,
			Data:      resp,
		},
	}

	h.logger.Info("Successfully created Basic", map[string]interface{}{
		"request_id": requestID,
	})

	c.JSON(http.StatusCreated, response)
}

// GetBasic retrieves a specific resource by ID
// @Summary Get a specific resource by ID
// @Description Retrieve a specific resource from the system
// @Tags Patient
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param id path string true "Resource ID"
// @Success 200 {object} models.PatientResponse "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 /:id [get]
func (h *Patient) GetBasic(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)
	}

	id := c.Param("id")
	if id == "" {

		h.logger.Error("Missing required parameter id", map[string]interface{}{
			"request_id": requestID,
		})

		c.JSON(http.StatusBadRequest, models.ErrorResponse{
			Status:    "error",
			Message:   "Missing required parameter id",
			RequestID: requestID,
		})
		return
	}

	h.logger.Info("Processing GetBasic request", map[string]interface{}{
		"request_id": requestID,
		"endpoint":   "/:id",
		"id":         id,
	})

	// Call SATUSEHAT service to get patient by ID
	resp, err := h.satusehatService.GetResourceByID(ctx, "Patient", id)
	if err != nil {
		h.logger.Error("Failed to get patient via SATUSEHAT", map[string]interface{}{
			"error":      err.Error(),
			"request_id": requestID,
			"id":         id,
		})

		c.JSON(http.StatusInternalServerError, models.ErrorResponse{
			Status:    "error",
			Message:   "Failed to get patient: " + err.Error(),
			RequestID: requestID,
		})
		return
	}

	response := models.PatientResponse{
		BaseResponse: models.BaseResponse{
			Status:    "success",
			Message:   "Patient retrieved successfully",
			RequestID: requestID,
			Data:      resp,
		},
	}

	h.logger.Info("Successfully retrieved Basic", map[string]interface{}{
		"request_id": requestID,
		"id":         id,
	})

	c.JSON(http.StatusOK, response)
}

// UpdateBasic updates an existing resource
// @Summary Update an existing resource
// @Description Update an existing resource in the system
// @Tags Patient
// @Accept json
// @Produce json
// @Param Authorization header string true "Bearer token"
// @Param id path string true "Resource ID"
// @Param request body models.BasicUpdateRequest true "Resource update request"
// @Success 200 {object} models.PatientResponse "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 /:id [put]
func (h *Patient) UpdateBasic(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)
	}

	id := c.Param("id")
	if id == "" {

		h.logger.Error("Missing required parameter id", map[string]interface{}{
			"request_id": requestID,
		})

		c.JSON(http.StatusBadRequest, models.ErrorResponse{
			Status:    "error",
			Message:   "Missing required parameter id",
			RequestID: requestID,
		})
		return
	}

	h.logger.Info("Processing UpdateBasic request", map[string]interface{}{
		"request_id": requestID,
		"endpoint":   "/:id",
		"id":         id,
	})

	// Bind and validate request body
	var req models.PatientUpdateRequest
	if err := c.ShouldBindJSON(&req); err != nil {

		h.logger.Error("Failed to bind request body", map[string]interface{}{
			"error":      err.Error(),
			"request_id": requestID,
		})

		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 {

		h.logger.Error("Request validation failed", map[string]interface{}{
			"error":      err.Error(),
			"request_id": requestID,
		})

		c.JSON(http.StatusBadRequest, models.ErrorResponse{
			Status:    "error",
			Message:   "Validation failed: " + err.Error(),
			RequestID: requestID,
		})
		return
	}

	// Call SATUSEHAT service to update patient
	resp := h.satusehatService.Put(ctx, "/Patient/"+id, req, &models.PatientResponse{})

	response := models.PatientResponse{
		BaseResponse: models.BaseResponse{
			Status:    "success",
			Message:   "Patient updated successfully",
			RequestID: requestID,
			Data:      resp,
		},
	}

	h.logger.Info("Successfully updated Basic", map[string]interface{}{
		"request_id": requestID,
		"id":         id,
	})

	c.JSON(http.StatusOK, response)
}

func (h *Patient) DeleteBasic(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)
	}

	id := c.Param("id")
	if id == "" {

		h.logger.Error("Missing required parameter id", map[string]interface{}{
			"request_id": requestID,
		})

		c.JSON(http.StatusBadRequest, models.ErrorResponse{
			Status:    "error",
			Message:   "Missing required parameter id",
			RequestID: requestID,
		})
		return
	}

	h.logger.Info("Processing DeleteBasic request", map[string]interface{}{
		"request_id": requestID,
		"endpoint":   "/:id",
		"id":         id,
	})

	// Call SATUSEHAT service to delete patient
	err := h.satusehatService.Delete(ctx, "/Patient/"+id, nil)
	if err != nil {
		h.logger.Error("Failed to delete patient via SATUSEHAT", map[string]interface{}{
			"error":      err.Error(),
			"request_id": requestID,
			"id":         id,
		})

		c.JSON(http.StatusInternalServerError, models.ErrorResponse{
			Status:    "error",
			Message:   "Failed to delete patient: " + err.Error(),
			RequestID: requestID,
		})
		return
	}

	response := models.SuccessResponse{
		Status:    "success",
		Message:   "Patient deleted successfully",
		RequestID: requestID,
	}

	h.logger.Info("Successfully deleted Patient", map[string]interface{}{
		"request_id": requestID,
		"id":         id,
	})

	c.JSON(http.StatusOK, response)
}

// SearchBasic searches for resources
// @Summary Search for resources
// @Description Search for resources in the system
// @Tags Patient
// @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.BasicSearchResponse "Search results"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 401 {object} models.ErrorResponse "Unauthorized"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router  [get]
func (h *Patient) SearchBasic(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)
	}

	// 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
		}
	}

	h.logger.Info("Processing SearchBasic request", map[string]interface{}{
		"request_id": requestID,
		"endpoint":   "",
		"query":      query,
		"limit":      limit,
		"offset":     offset,
	})

	// Build search query for SATUSEHAT
	endpoint := "/Patient"
	if query != "" {
		endpoint += "?name=" + query
	}
	if limit > 0 {
		if query == "" {
			endpoint += "?"
		} else {
			endpoint += "&"
		}
		endpoint += "_count=" + strconv.Itoa(limit)
	}

	// Call SATUSEHAT service to search patients
	resp, err := h.satusehatService.GetRawResponse(ctx, endpoint)
	if err != nil {
		h.logger.Error("Failed to search patients via SATUSEHAT", map[string]interface{}{
			"error":      err.Error(),
			"request_id": requestID,
			"query":      query,
		})

		c.JSON(http.StatusInternalServerError, models.ErrorResponse{
			Status:    "error",
			Message:   "Failed to search patients: " + err.Error(),
			RequestID: requestID,
		})
		return
	}

	response := models.PatientSearchResponse{
		BaseResponse: models.BaseResponse{
			Status:    "success",
			Message:   "Search completed successfully",
			RequestID: requestID,
			Data:      resp,
		},
	}

	h.logger.Info("Successfully completed search", map[string]interface{}{
		"request_id": requestID,
		"query":      query,
		"results":    len(response.Data.Results),
	})

	c.JSON(http.StatusOK, response)
}
