package service

import (
	"context"
	"errors"
	"fmt"
	"time"

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

// Interfaces for dependency inversion (DIP) — service layer depends on these abstractions, not concrete types.
type deviceRepository interface {
	Create(ctx context.Context, device *domain.Device) error
	Update(ctx context.Context, device *domain.Device) error
	Delete(ctx context.Context, id int64) error
	GetByID(ctx context.Context, id int64) (*domain.Device, error)
	GetByDeviceID(ctx context.Context, userID int64, deviceID string) (*domain.Device, error)
	Exists(ctx context.Context, userID int64, deviceID string) (bool, error)
	ListByUserID(ctx context.Context, userID int64, offset, limit int) ([]*domain.Device, int64, error)
	ListByStatus(ctx context.Context, status domain.DeviceStatus, offset, limit int) ([]*domain.Device, int64, error)
	UpdateStatus(ctx context.Context, id int64, status domain.DeviceStatus) error
	UpdateLastActiveTime(ctx context.Context, id int64) error
	TrustDevice(ctx context.Context, id int64, expiresAt *time.Time) error
	UntrustDevice(ctx context.Context, id int64) error
	DeleteAllByUserIDExcept(ctx context.Context, userID int64, exceptDeviceID int64) error
	GetTrustedDevices(ctx context.Context, userID int64) ([]*domain.Device, error)
	ListAll(ctx context.Context, params *repository.ListDevicesParams) ([]*domain.Device, int64, error)
	ListAllCursor(ctx context.Context, params *repository.ListDevicesParams, limit int, cursor *pagination.Cursor) ([]*domain.Device, bool, error)
}

type deviceUserRepository interface {
	GetByID(ctx context.Context, id int64) (*domain.User, error)
}

// DeviceService 设备服务
type DeviceService struct {
	deviceRepo deviceRepository
	userRepo   deviceUserRepository
}

// NewDeviceService 创建设备服务
func NewDeviceService(
	deviceRepo deviceRepository,
	userRepo deviceUserRepository,
) *DeviceService {
	return &DeviceService{
		deviceRepo: deviceRepo,
		userRepo:   userRepo,
	}
}

// CreateDeviceRequest 创建设备请求
type CreateDeviceRequest struct {
	DeviceID      string `json:"device_id" binding:"required"`
	DeviceName    string `json:"device_name"`
	DeviceType    int    `json:"device_type"`
	DeviceOS      string `json:"device_os"`
	DeviceBrowser string `json:"device_browser"`
	IP            string `json:"ip"`
	Location      string `json:"location"`
}

// UpdateDeviceRequest 更新设备请求
type UpdateDeviceRequest struct {
	DeviceName    string `json:"device_name"`
	DeviceType    int    `json:"device_type"`
	DeviceOS      string `json:"device_os"`
	DeviceBrowser string `json:"device_browser"`
	IP            string `json:"ip"`
	Location      string `json:"location"`
	Status        int    `json:"status"`
}

// CreateDevice 创建设备
func (s *DeviceService) CreateDevice(ctx context.Context, userID int64, req *CreateDeviceRequest) (*domain.Device, error) {
	// 检查用户是否存在
	_, err := s.userRepo.GetByID(ctx, userID)
	if err != nil {
		return nil, errors.New("用户不存在")
	}

	// 检查设备是否已存在
	exists, err := s.deviceRepo.Exists(ctx, userID, req.DeviceID)
	if err != nil {
		return nil, err
	}
	if exists {
		// 设备已存在，更新最后活跃时间
		device, err := s.deviceRepo.GetByDeviceID(ctx, userID, req.DeviceID)
		if err != nil {
			return nil, err
		}
		device.LastActiveTime = time.Now()
		return device, s.deviceRepo.Update(ctx, device)
	}

	// 创建设备
	device := &domain.Device{
		UserID:        userID,
		DeviceID:      req.DeviceID,
		DeviceName:    req.DeviceName,
		DeviceType:    domain.DeviceType(req.DeviceType),
		DeviceOS:      req.DeviceOS,
		DeviceBrowser: req.DeviceBrowser,
		IP:            req.IP,
		Location:      req.Location,
		Status:        domain.DeviceStatusActive,
	}

	if err := s.deviceRepo.Create(ctx, device); err != nil {
		return nil, err
	}

	return device, nil
}

// UpdateDevice 更新设备
func (s *DeviceService) UpdateDevice(ctx context.Context, deviceID int64, req *UpdateDeviceRequest) (*domain.Device, error) {
	device, err := s.deviceRepo.GetByID(ctx, deviceID)
	if err != nil {
		return nil, errors.New("设备不存在")
	}

	// 更新字段
	if req.DeviceName != "" {
		device.DeviceName = req.DeviceName
	}
	if req.DeviceType >= 0 {
		device.DeviceType = domain.DeviceType(req.DeviceType)
	}
	if req.DeviceOS != "" {
		device.DeviceOS = req.DeviceOS
	}
	if req.DeviceBrowser != "" {
		device.DeviceBrowser = req.DeviceBrowser
	}
	if req.IP != "" {
		device.IP = req.IP
	}
	if req.Location != "" {
		device.Location = req.Location
	}
	if req.Status >= 0 {
		device.Status = domain.DeviceStatus(req.Status)
	}

	if err := s.deviceRepo.Update(ctx, device); err != nil {
		return nil, err
	}

	return device, nil
}

// DeleteDevice 删除设备
func (s *DeviceService) DeleteDevice(ctx context.Context, deviceID int64) error {
	return s.deviceRepo.Delete(ctx, deviceID)
}

// GetDevice 获取设备信息
func (s *DeviceService) GetDevice(ctx context.Context, deviceID int64) (*domain.Device, error) {
	return s.deviceRepo.GetByID(ctx, deviceID)
}

// GetUserDevices 获取用户设备列表
func (s *DeviceService) GetUserDevices(ctx context.Context, userID int64, page, pageSize int) ([]*domain.Device, int64, error) {
	offset := (page - 1) * pageSize
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}

	return s.deviceRepo.ListByUserID(ctx, userID, offset, pageSize)
}

// UpdateDeviceStatus 更新设备状态
func (s *DeviceService) UpdateDeviceStatus(ctx context.Context, deviceID int64, status domain.DeviceStatus) error {
	return s.deviceRepo.UpdateStatus(ctx, deviceID, status)
}

// UpdateLastActiveTime 更新最后活跃时间
func (s *DeviceService) UpdateLastActiveTime(ctx context.Context, deviceID int64) error {
	return s.deviceRepo.UpdateLastActiveTime(ctx, deviceID)
}

// GetActiveDevices 获取活跃设备
func (s *DeviceService) GetActiveDevices(ctx context.Context, page, pageSize int) ([]*domain.Device, int64, error) {
	offset := (page - 1) * pageSize
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 20
	}

	return s.deviceRepo.ListByStatus(ctx, domain.DeviceStatusActive, offset, pageSize)
}

// TrustDevice 设置设备为信任状态
func (s *DeviceService) TrustDevice(ctx context.Context, deviceID int64, trustDuration time.Duration) error {
	device, err := s.deviceRepo.GetByID(ctx, deviceID)
	if err != nil {
		return errors.New("设备不存在")
	}

	var trustExpiresAt *time.Time
	if trustDuration > 0 {
		expiresAt := time.Now().Add(trustDuration)
		trustExpiresAt = &expiresAt
	}

	return s.deviceRepo.TrustDevice(ctx, device.ID, trustExpiresAt)
}

// TrustDeviceByDeviceID 根据设备标识字符串设置设备为信任状态
func (s *DeviceService) TrustDeviceByDeviceID(ctx context.Context, userID int64, deviceID string, trustDuration time.Duration) error {
	device, err := s.deviceRepo.GetByDeviceID(ctx, userID, deviceID)
	if err != nil {
		return errors.New("设备不存在")
	}

	var trustExpiresAt *time.Time
	if trustDuration > 0 {
		expiresAt := time.Now().Add(trustDuration)
		trustExpiresAt = &expiresAt
	}

	return s.deviceRepo.TrustDevice(ctx, device.ID, trustExpiresAt)
}

// UntrustDevice 取消设备信任状态
func (s *DeviceService) UntrustDevice(ctx context.Context, deviceID int64) error {
	device, err := s.deviceRepo.GetByID(ctx, deviceID)
	if err != nil {
		return errors.New("设备不存在")
	}

	return s.deviceRepo.UntrustDevice(ctx, device.ID)
}

// LogoutAllOtherDevices 登出所有其他设备
func (s *DeviceService) LogoutAllOtherDevices(ctx context.Context, userID int64, currentDeviceID int64) error {
	return s.deviceRepo.DeleteAllByUserIDExcept(ctx, userID, currentDeviceID)
}

// GetTrustedDevices 获取用户的信任设备列表
func (s *DeviceService) GetTrustedDevices(ctx context.Context, userID int64) ([]*domain.Device, error) {
	return s.deviceRepo.GetTrustedDevices(ctx, userID)
}

// GetAllDevicesRequest 获取所有设备请求参数
type GetAllDevicesRequest struct {
	Page      int    `form:"page"`
	PageSize  int    `form:"page_size"`
	UserID    int64  `form:"user_id"`
	Status    *int   `form:"status"` // 0-禁用, 1-激活, nil-不筛选
	IsTrusted *bool  `form:"is_trusted"`
	Keyword   string `form:"keyword"`
	Cursor    string `form:"cursor"` // Opaque cursor for keyset pagination
	Size      int    `form:"size"`   // Page size when using cursor mode
}

// GetAllDevices 获取所有设备（管理员用）
func (s *DeviceService) GetAllDevices(ctx context.Context, req *GetAllDevicesRequest) ([]*domain.Device, int64, error) {
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}
	if req.PageSize > 100 {
		req.PageSize = 100
	}

	offset := (req.Page - 1) * req.PageSize

	params := &repository.ListDevicesParams{
		UserID:  req.UserID,
		Keyword: req.Keyword,
		Offset:  offset,
		Limit:   req.PageSize,
	}

	// 处理状态筛选（仅当明确指定了状态时才筛选）
	if req.Status != nil && (*req.Status == 0 || *req.Status == 1) {
		status := domain.DeviceStatus(*req.Status)
		params.Status = &status
	}

	// 处理信任状态筛选
	if req.IsTrusted != nil {
		params.IsTrusted = req.IsTrusted
	}

	return s.deviceRepo.ListAll(ctx, params)
}

// GetAllDevicesCursor 游标分页获取所有设备（推荐使用）
func (s *DeviceService) GetAllDevicesCursor(ctx context.Context, req *GetAllDevicesRequest) (*CursorResult, error) {
	size := pagination.ClampPageSize(req.Size)
	if req.PageSize > 0 && req.Cursor == "" {
		size = pagination.ClampPageSize(req.PageSize)
	}

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

	params := &repository.ListDevicesParams{
		UserID:  req.UserID,
		Keyword: req.Keyword,
	}
	if req.Status != nil && (*req.Status == 0 || *req.Status == 1) {
		status := domain.DeviceStatus(*req.Status)
		params.Status = &status
	}
	if req.IsTrusted != nil {
		params.IsTrusted = req.IsTrusted
	}

	devices, hasMore, err := s.deviceRepo.ListAllCursor(ctx, params, size, cursor)
	if err != nil {
		return nil, err
	}

	nextCursor := ""
	if len(devices) > 0 {
		last := devices[len(devices)-1]
		nextCursor = pagination.BuildNextCursor(last.ID, last.LastActiveTime)
	}

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

// GetDeviceByDeviceID 根据设备标识获取设备（用于设备信任检查）
func (s *DeviceService) GetDeviceByDeviceID(ctx context.Context, userID int64, deviceID string) (*domain.Device, error) {
	return s.deviceRepo.GetByDeviceID(ctx, userID, deviceID)
}
