package grpc

import (
	"context"
	"time"

	userv1 "hyapp.local/api/proto/user/v1"
	"hyapp/pkg/xerr"
	userdomain "hyapp/services/user-service/internal/domain/user"
	authservice "hyapp/services/user-service/internal/service/auth"
	mictimeservice "hyapp/services/user-service/internal/service/mictime"
	userservice "hyapp/services/user-service/internal/service/user"
)

// ProcessLoginIPRiskBatch 处理一批登录后 IP 风控任务，任务 claim 和 session revoke 仍在 user-service 内完成。
func (s *Server) ProcessLoginIPRiskBatch(ctx context.Context, req *userv1.CronBatchRequest) (*userv1.CronBatchResponse, error) {
	ctx = contextWithApp(ctx, req.GetMeta())
	if s.authSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "auth service is not configured"))
	}
	processed, err := s.authSvc.ProcessLoginIPRiskBatch(ctx, authservice.LoginIPRiskWorkerOptions{
		WorkerID:  req.GetWorkerId(),
		LockTTL:   durationFromMillis(req.GetLockTtlMs()),
		BatchSize: int(req.GetBatchSize()),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CronBatchResponse{
		ClaimedCount:   int32(processed),
		ProcessedCount: int32(processed),
		SuccessCount:   int32(processed),
		HasMore:        processed >= normalizedBatchSize(req.GetBatchSize(), 100),
	}, nil
}

// ProcessRegionRebuildBatch 处理一个区域重算分页任务，按 app_code 作用域 claim。
func (s *Server) ProcessRegionRebuildBatch(ctx context.Context, req *userv1.CronBatchRequest) (*userv1.CronBatchResponse, error) {
	ctx = contextWithApp(ctx, req.GetMeta())
	if s.userSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "user service is not configured"))
	}
	result, err := s.userSvc.ProcessNextRegionRebuildTask(ctx, userservice.RegionRebuildWorkerOptions{
		WorkerID:  req.GetWorkerId(),
		LockTTL:   durationFromMillis(req.GetLockTtlMs()),
		BatchSize: int(req.GetBatchSize()),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	if result.NoTask {
		return &userv1.CronBatchResponse{}, nil
	}
	return &userv1.CronBatchResponse{
		ClaimedCount:   1,
		ProcessedCount: int32(result.ProcessedUsers),
		SuccessCount:   1,
		HasMore:        result.Status == userdomain.RegionRebuildTaskStatusPending,
	}, nil
}

// CompensateMicOpenSessions 关闭异常长时间未收到 down 事件的用户麦位统计 session，不反写 Room Cell。
func (s *Server) CompensateMicOpenSessions(ctx context.Context, req *userv1.CronBatchRequest) (*userv1.CronBatchResponse, error) {
	ctx = contextWithApp(ctx, req.GetMeta())
	if s.micTimeSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "mic time service is not configured"))
	}
	result, err := s.micTimeSvc.ProcessOpenSessionCompensationBatch(ctx, mictimeservice.CompensationWorkerOptions{
		WorkerID:                req.GetWorkerId(),
		BatchSize:               int(req.GetBatchSize()),
		PendingPublishMaxAge:    durationFromMillis(req.GetPendingPublishMaxAgeMs()),
		PublishingSessionMaxAge: durationFromMillis(req.GetPublishingSessionMaxAgeMs()),
	})
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CronBatchResponse{
		ClaimedCount:   int32(result.ClosedCount),
		ProcessedCount: int32(result.ClosedCount),
		SuccessCount:   int32(result.ClosedCount),
		HasMore:        result.ClosedCount >= normalizedBatchSize(req.GetBatchSize(), 100),
	}, nil
}

// ExpireManagerUserBlocks 释放到期的经理封禁记录；真正是否恢复 users.status 由 user-service 内部封禁来源判断。
func (s *Server) ExpireManagerUserBlocks(ctx context.Context, req *userv1.CronBatchRequest) (*userv1.CronBatchResponse, error) {
	ctx = contextWithApp(ctx, req.GetMeta())
	if s.userSvc == nil {
		return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "user service is not configured"))
	}
	processed, err := s.userSvc.ExpireManagerUserBlocks(ctx, req.GetBatchSize())
	if err != nil {
		return nil, xerr.ToGRPCError(err)
	}
	return &userv1.CronBatchResponse{
		ClaimedCount:   int32(processed),
		ProcessedCount: int32(processed),
		SuccessCount:   int32(processed),
		HasMore:        processed >= normalizedBatchSize(req.GetBatchSize(), 100),
	}, nil
}

func durationFromMillis(value int64) time.Duration {
	if value <= 0 {
		return 0
	}
	return time.Duration(value) * time.Millisecond
}

func normalizedBatchSize(value int32, fallback int) int {
	if value <= 0 {
		return fallback
	}
	return int(value)
}
