package handlers

import (
	"Yimaru-Backend/internal/domain"
	"encoding/json"
	"strconv"
	"time"

	"github.com/gofiber/fiber/v2"
)

type activityLogRes struct {
	ID           int64           `json:"id"`
	ActorID      *int64          `json:"actor_id,omitempty"`
	ActorRole    *string         `json:"actor_role,omitempty"`
	Action       string          `json:"action"`
	ResourceType string          `json:"resource_type"`
	ResourceID   *int64          `json:"resource_id,omitempty"`
	Message      *string         `json:"message,omitempty"`
	Metadata     json.RawMessage `json:"metadata"`
	IPAddress    *string         `json:"ip_address,omitempty"`
	UserAgent    *string         `json:"user_agent,omitempty"`
	CreatedAt    time.Time       `json:"created_at"`
}

type activityLogListRes struct {
	Logs       []activityLogRes `json:"logs"`
	TotalCount int64            `json:"total_count"`
	Limit      int32            `json:"limit"`
	Offset     int32            `json:"offset"`
}

// GetActivityLogs godoc
// @Summary Get activity logs
// @Description Returns a filtered, paginated list of activity logs
// @Tags activity-logs
// @Produce json
// @Param actor_id query int false "Filter by actor ID"
// @Param action query string false "Filter by action"
// @Param resource_type query string false "Filter by resource type"
// @Param resource_id query int false "Filter by resource ID"
// @Param after query string false "Filter logs after this RFC3339 timestamp"
// @Param before query string false "Filter logs before this RFC3339 timestamp"
// @Param limit query int false "Limit" default(20)
// @Param offset query int false "Offset" default(0)
// @Success 200 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/activity-logs [get]
func (h *Handler) GetActivityLogs(c *fiber.Ctx) error {
	var filter domain.ActivityLogFilter

	if v := c.Query("actor_id"); v != "" {
		id, err := strconv.ParseInt(v, 10, 64)
		if err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Invalid actor_id parameter",
				Error:   err.Error(),
			})
		}
		filter.ActorID = &id
	}

	if v := c.Query("action"); v != "" {
		filter.Action = &v
	}

	if v := c.Query("resource_type"); v != "" {
		filter.ResourceType = &v
	}

	if v := c.Query("resource_id"); v != "" {
		id, err := strconv.ParseInt(v, 10, 64)
		if err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Invalid resource_id parameter",
				Error:   err.Error(),
			})
		}
		filter.ResourceID = &id
	}

	if v := c.Query("after"); v != "" {
		t, err := time.Parse(time.RFC3339, v)
		if err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Invalid after parameter, expected RFC3339 format",
				Error:   err.Error(),
			})
		}
		filter.After = &t
	}

	if v := c.Query("before"); v != "" {
		t, err := time.Parse(time.RFC3339, v)
		if err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Invalid before parameter, expected RFC3339 format",
				Error:   err.Error(),
			})
		}
		filter.Before = &t
	}

	limitStr := c.Query("limit", "20")
	limit, err := strconv.Atoi(limitStr)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid limit parameter",
			Error:   err.Error(),
		})
	}
	if limit > 100 {
		limit = 100
	}
	filter.Limit = int32(limit)

	offsetStr := c.Query("offset", "0")
	offset, err := strconv.Atoi(offsetStr)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid offset parameter",
			Error:   err.Error(),
		})
	}
	filter.Offset = int32(offset)

	logs, totalCount, err := h.activityLogSvc.List(c.Context(), filter)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to retrieve activity logs",
			Error:   err.Error(),
		})
	}

	var logResponses []activityLogRes
	for _, l := range logs {
		logResponses = append(logResponses, activityLogRes{
			ID:           l.ID,
			ActorID:      l.ActorID,
			ActorRole:    l.ActorRole,
			Action:       l.Action,
			ResourceType: l.ResourceType,
			ResourceID:   l.ResourceID,
			Message:      l.Message,
			Metadata:     l.Metadata,
			IPAddress:    l.IPAddress,
			UserAgent:    l.UserAgent,
			CreatedAt:    l.CreatedAt,
		})
	}

	return c.JSON(domain.Response{
		Message: "Activity logs retrieved successfully",
		Data: activityLogListRes{
			Logs:       logResponses,
			TotalCount: totalCount,
			Limit:      int32(limit),
			Offset:     int32(offset),
		},
	})
}

// GetActivityLogByID godoc
// @Summary Get activity log by ID
// @Description Returns a single activity log entry by its ID
// @Tags activity-logs
// @Produce json
// @Param id path int true "Activity Log ID"
// @Success 200 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 404 {object} domain.ErrorResponse
// @Router /api/v1/activity-logs/{id} [get]
func (h *Handler) GetActivityLogByID(c *fiber.Ctx) error {
	idStr := c.Params("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid activity log ID",
			Error:   err.Error(),
		})
	}

	l, err := h.activityLogSvc.GetByID(c.Context(), id)
	if err != nil {
		return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
			Message: "Activity log not found",
			Error:   err.Error(),
		})
	}

	return c.JSON(domain.Response{
		Message: "Activity log retrieved successfully",
		Data: activityLogRes{
			ID:           l.ID,
			ActorID:      l.ActorID,
			ActorRole:    l.ActorRole,
			Action:       l.Action,
			ResourceType: l.ResourceType,
			ResourceID:   l.ResourceID,
			Message:      l.Message,
			Metadata:     l.Metadata,
			IPAddress:    l.IPAddress,
			UserAgent:    l.UserAgent,
			CreatedAt:    l.CreatedAt,
		},
	})
}
