package service

import (
	"context"
	"fmt"
	"time"

	"github.com/user-management-system/internal/domain"
	"github.com/user-management-system/internal/pagination"
	"github.com/user-management-system/internal/repository"
)

// OperationLogService 操作日志服务
type OperationLogService struct {
	operationLogRepo *repository.OperationLogRepository
}

// NewOperationLogService 创建操作日志服务
func NewOperationLogService(operationLogRepo *repository.OperationLogRepository) *OperationLogService {
	return &OperationLogService{operationLogRepo: operationLogRepo}
}

// RecordOperation 记录操作日志
func (s *OperationLogService) RecordOperation(ctx context.Context, req *RecordOperationRequest) error {
	log := &domain.OperationLog{
		OperationType:  req.OperationType,
		OperationName:  req.OperationName,
		RequestMethod:  req.RequestMethod,
		RequestPath:    req.RequestPath,
		RequestParams:  req.RequestParams,
		ResponseStatus: req.ResponseStatus,
		IP:             req.IP,
		UserAgent:      req.UserAgent,
	}
	if req.UserID != 0 {
		log.UserID = &req.UserID
	}
	return s.operationLogRepo.Create(ctx, log)
}

// RecordOperationRequest 记录操作请求
type RecordOperationRequest struct {
	UserID         int64  `json:"user_id"`
	OperationType  string `json:"operation_type"`
	OperationName  string `json:"operation_name"`
	RequestMethod  string `json:"request_method"`
	RequestPath    string `json:"request_path"`
	RequestParams  string `json:"request_params"`
	ResponseStatus int    `json:"response_status"`
	IP             string `json:"ip"`
	UserAgent      string `json:"user_agent"`
}

// ListOperationLogRequest 操作日志列表请求
type ListOperationLogRequest struct {
	UserID   int64  `json:"user_id" form:"user_id"`
	Method   string `json:"method" form:"method"`
	Keyword  string `json:"keyword" form:"keyword"`
	Page     int    `json:"page" form:"page"`
	PageSize int    `json:"page_size" form:"page_size"`
	StartAt  string `json:"start_at" form:"start_at"`
	EndAt    string `json:"end_at" form:"end_at"`
	Cursor   string `form:"cursor"` // Opaque cursor for keyset pagination
	Size     int    `form:"size"`   // Page size when using cursor mode
}

// GetOperationLogs 获取操作日志列表
func (s *OperationLogService) GetOperationLogs(ctx context.Context, req *ListOperationLogRequest) ([]*domain.OperationLog, int64, error) {
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}
	offset := (req.Page - 1) * req.PageSize

	// 按关键词搜索
	if req.Keyword != "" {
		return s.operationLogRepo.Search(ctx, req.Keyword, offset, req.PageSize)
	}

	// 按用户 ID 查询
	if req.UserID > 0 {
		return s.operationLogRepo.ListByUserID(ctx, req.UserID, offset, req.PageSize)
	}

	// 按 HTTP 方法查询
	if req.Method != "" {
		return s.operationLogRepo.ListByMethod(ctx, req.Method, offset, req.PageSize)
	}

	// 按时间范围查询
	if req.StartAt != "" && req.EndAt != "" {
		start, err1 := time.Parse(time.RFC3339, req.StartAt)
		end, err2 := time.Parse(time.RFC3339, req.EndAt)
		if err1 == nil && err2 == nil {
			return s.operationLogRepo.ListByTimeRange(ctx, start, end, offset, req.PageSize)
		}
	}

	return s.operationLogRepo.List(ctx, offset, req.PageSize)
}

// GetOperationLogsCursor 游标分页获取操作日志列表（推荐使用）
func (s *OperationLogService) GetOperationLogsCursor(ctx context.Context, req *ListOperationLogRequest) (*CursorResult, error) {
	size := pagination.ClampPageSize(req.Size)

	cursor, err := pagination.Decode(req.Cursor)
	if err != nil {
		return nil, fmt.Errorf("invalid cursor: %w", err)
	}

	var items interface{}
	var hasMore bool

	logs, hm, err := s.operationLogRepo.ListCursor(ctx, size, cursor)
	if err != nil {
		return nil, err
	}
	items = logs
	hasMore = hm

	nextCursor := ""
	switch items := items.(type) {
	case []*domain.OperationLog:
		if len(items) > 0 {
			last := items[len(items)-1]
			nextCursor = pagination.BuildNextCursor(last.ID, last.CreatedAt)
		}
	}

	return &CursorResult{
		Items:      items,
		NextCursor: nextCursor,
		HasMore:    hasMore,
		PageSize:   size,
	}, nil
}

// GetMyOperationLogs 获取当前用户的操作日志
func (s *OperationLogService) GetMyOperationLogs(ctx context.Context, userID int64, page, pageSize int) ([]*domain.OperationLog, int64, error) {
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}
	offset := (page - 1) * pageSize
	return s.operationLogRepo.ListByUserID(ctx, userID, offset, pageSize)
}

// CleanupOldLogs 清理旧日志（保留最近 N 天）
func (s *OperationLogService) CleanupOldLogs(ctx context.Context, retentionDays int) error {
	return s.operationLogRepo.DeleteOlderThan(ctx, retentionDays)
}
