// internal/controllers/item_controller.go	
package controllers

import (
	"lost-and-found/internal/models"
	"lost-and-found/internal/services"
	"lost-and-found/internal/repositories" // ✅ TAMBAHKAN INI
	"lost-and-found/internal/utils"
	"net/http"
	"strconv"
	"log"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type ItemController struct {
	itemService  *services.ItemService
	matchService *services.MatchService
	itemRepo     *repositories.ItemRepository // ✅ TAMBAHKAN INI
}

func NewItemController(db *gorm.DB) *ItemController {
	return &ItemController{
		itemService:  services.NewItemService(db),
		matchService: services.NewMatchService(db),
		itemRepo:     repositories.NewItemRepository(db), // ✅ INITIALIZE INI
	}
}

// ✅ FIXED GetItemByID
// ✅ PASTIKAN response detail lengkap untuk manager
// ✅ FIXED GetItemByIDfunc (c *ItemController) GetItemByID(ctx *gin.Context) {
// ✅ FIXED GetItemByID - NOW RETURNS FULL DETAILS FOR MANAGER
func (c *ItemController) GetItemByID(ctx *gin.Context) {
	id, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid item ID", err.Error())
		return
	}

	// ✅ Check if user is manager or admin
	isManager := false
	if userObj, exists := ctx.Get("user"); exists {
		user := userObj.(*models.User)
		isManager = user.IsManager() || user.IsAdmin()
	}

	// ✅ Get item DIRECTLY from repository with PRELOAD
	item, err := c.itemRepo.FindByID(uint(id))
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusNotFound, "Item not found", err.Error())
		return
	}

	// ✅ LOG untuk debug
	log.Printf("🔍 Controller GetItemByID - Item ID: %d", item.ID)
	log.Printf("   📝 Description: %s", item.Description)
	log.Printf("   🔒 SecretDetails: %s", item.SecretDetails)
	log.Printf("   👤 ReporterName: %s", item.ReporterName)
	log.Printf("   📞 ReporterContact: %s", item.ReporterContact)

	// ✅ Return response based on role
	if isManager {
		// Manager/Admin gets FULL details
		detailResponse := item.ToDetailResponse()
		
		// ✅ LOG response yang akan dikirim
		log.Printf("📤 Sending DetailResponse to Manager:")
		log.Printf("   Description: %s", detailResponse.Description)
		log.Printf("   SecretDetails: %s", detailResponse.SecretDetails)
		log.Printf("   ReporterName: %s", detailResponse.ReporterName)
		
		utils.SuccessResponse(ctx, http.StatusOK, "Item retrieved", detailResponse)
	} else {
		// Regular user gets public view only
		utils.SuccessResponse(ctx, http.StatusOK, "Item retrieved", item.ToPublicResponse())
	}
}

func (c *ItemController) ReportFoundItemLinked(ctx *gin.Context) {
    userObj, _ := ctx.Get("user")
    user := userObj.(*models.User)

    var req services.CreateFoundItemLinkedRequest
    if err := ctx.ShouldBindJSON(&req); err != nil {
        utils.ErrorResponse(ctx, http.StatusBadRequest, "Data tidak valid", err.Error())
        return
    }

    ipAddress := ctx.ClientIP()
    userAgent := ctx.Request.UserAgent()

    item, err := c.itemService.CreateFoundItemLinked(user.ID, req, ipAddress, userAgent)
    if err != nil {
        utils.ErrorResponse(ctx, http.StatusInternalServerError, "Gagal membuat laporan", err.Error())
        return
    }

    message := "Laporan berhasil dibuat. Menunggu verifikasi Manager."
    if req.IsDirectToOwner {
        message = "Laporan berhasil! Notifikasi langsung dikirim ke pemilik barang."
    }

    utils.SuccessResponse(ctx, http.StatusCreated, message, item)
}
// CreateItem creates a new item
// POST /api/items
func (c *ItemController) CreateItem(ctx *gin.Context) {
	userObj, _ := ctx.Get("user")
	user := userObj.(*models.User)

	var req services.CreateItemRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid request data", err.Error())
		return
	}

	ipAddress := ctx.ClientIP()
	userAgent := ctx.Request.UserAgent()

	item, err := c.itemService.CreateItem(user.ID, req, ipAddress, userAgent)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Failed to create item", err.Error())
		return
	}

	// Auto-match with lost items
	go c.matchService.AutoMatchNewItem(item.ID)

	utils.SuccessResponse(ctx, http.StatusCreated, "Item created", item.ToDetailResponse())
}

// UpdateItem updates an item
// PUT /api/items/:id
func (c *ItemController) UpdateItem(ctx *gin.Context) {
	userObj, _ := ctx.Get("user")
	user := userObj.(*models.User)

	itemID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid item ID", err.Error())
		return
	}

	var req services.UpdateItemRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid request data", err.Error())
		return
	}

	ipAddress := ctx.ClientIP()
	userAgent := ctx.Request.UserAgent()

	item, err := c.itemService.UpdateItem(user.ID, uint(itemID), req, ipAddress, userAgent)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Failed to update item", err.Error())
		return
	}

	utils.SuccessResponse(ctx, http.StatusOK, "Item updated", item.ToDetailResponse())
}

// UpdateItemStatus updates item status
// PATCH /api/items/:id/status
func (c *ItemController) UpdateItemStatus(ctx *gin.Context) {
	userObj, _ := ctx.Get("user")
	user := userObj.(*models.User)

	itemID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid item ID", err.Error())
		return
	}

	var req struct {
		Status string `json:"status" binding:"required"`
	}
	if err := ctx.ShouldBindJSON(&req); err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid request data", err.Error())
		return
	}

	ipAddress := ctx.ClientIP()
	userAgent := ctx.Request.UserAgent()

	if err := c.itemService.UpdateItemStatus(user.ID, uint(itemID), req.Status, ipAddress, userAgent); err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Failed to update status", err.Error())
		return
	}

	utils.SuccessResponse(ctx, http.StatusOK, "Item status updated", nil)
}

// DeleteItem deletes an item
// DELETE /api/items/:id
func (c *ItemController) DeleteItem(ctx *gin.Context) {
	userObj, _ := ctx.Get("user")
	user := userObj.(*models.User)

	itemID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid item ID", err.Error())
		return
	}

	ipAddress := ctx.ClientIP()
	userAgent := ctx.Request.UserAgent()

	if err := c.itemService.DeleteItem(user.ID, uint(itemID), ipAddress, userAgent); err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Failed to delete item", err.Error())
		return
	}

	utils.SuccessResponse(ctx, http.StatusOK, "Item deleted", nil)
}

// GetItemsByReporter gets items by reporter
// GET /api/user/items
func (c *ItemController) GetItemsByReporter(ctx *gin.Context) {
	userObj, _ := ctx.Get("user")
	user := userObj.(*models.User)

	page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10"))

	items, total, err := c.itemService.GetItemsByReporter(user.ID, page, limit)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "Failed to get items", err.Error())
		return
	}

	var responses []models.ItemDetailResponse
	for _, item := range items {
		responses = append(responses, item.ToDetailResponse())
	}

	utils.SendPaginatedResponse(ctx, http.StatusOK, "Items retrieved", responses, total, page, limit)
}

// GetItemRevisionHistory gets revision history for an item
// GET /api/items/:id/revisions
func (c *ItemController) GetItemRevisionHistory(ctx *gin.Context) {
	itemID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusBadRequest, "Invalid item ID", err.Error())
		return
	}

	page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10"))

	revisions, total, err := c.itemService.GetItemRevisionHistory(uint(itemID), page, limit)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "Failed to get revision history", err.Error())
		return
	}

	utils.SendPaginatedResponse(ctx, http.StatusOK, "Revision history retrieved", revisions, total, page, limit)
}

func (c *ItemController) GetAllItems(ctx *gin.Context) {
	page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(ctx.DefaultQuery("limit", "10"))
	status := ctx.Query("status")
	category := ctx.Query("category")
	search := ctx.Query("search")

	// ✅ CHECK IF USER IS MANAGER/ADMIN
	isManager := false
	if userObj, exists := ctx.Get("user"); exists {
		user := userObj.(*models.User)
		isManager = user.IsManager() || user.IsAdmin()
	}

	// ✅ FIXED: FORCE FILTER OUT EXPIRED for public users
	if !isManager {
        // 1. Jika user mencoba meminta status terlarang, paksa filter aman
        if status == models.ItemStatusExpired || status == models.ItemStatusCaseClosed {
            status = "!expired"
        }
        
        // 2. Jika status kosong (default), set ke !expired
        if status == "" {
            status = "!expired" 
        }
    }

	items, total, err := c.itemService.GetAllItems(page, limit, status, category, search)
	if err != nil {
		utils.ErrorResponse(ctx, http.StatusInternalServerError, "Failed to get items", err.Error())
		return
	}

	utils.SendPaginatedResponse(ctx, http.StatusOK, "Items retrieved", items, total, page, limit)
}