package apikeys

import (
	"context"
	"errors"
	"time"

	entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
	"gorm.io/gorm"
)

type Repository interface {
	Create(ctx context.Context, record *entity.IntegrationAPIKey) error
	GetByEnvironmentAndPrefix(ctx context.Context, environment, prefix string) (*entity.IntegrationAPIKey, error)
	List(ctx context.Context, environment string) ([]entity.IntegrationAPIKey, error)
	Revoke(ctx context.Context, environment, prefix string, revokedAt time.Time) error
	TouchLastUsed(ctx context.Context, id uint, usedAt time.Time, usedFrom string) error
}

type repository struct {
	db *gorm.DB
}

func NewRepository(db *gorm.DB) Repository {
	return &repository{db: db}
}

func (r *repository) Create(ctx context.Context, record *entity.IntegrationAPIKey) error {
	if r.db == nil {
		return errors.New("database not configured")
	}
	return r.db.WithContext(ctx).Create(record).Error
}

func (r *repository) GetByEnvironmentAndPrefix(ctx context.Context, environment, prefix string) (*entity.IntegrationAPIKey, error) {
	if r.db == nil {
		return nil, errors.New("database not configured")
	}

	var record entity.IntegrationAPIKey
	if err := r.db.WithContext(ctx).
		Where("environment = ?", environment).
		Where("key_prefix = ?", prefix).
		First(&record).Error; err != nil {
		return nil, err
	}

	return &record, nil
}

func (r *repository) List(ctx context.Context, environment string) ([]entity.IntegrationAPIKey, error) {
	if r.db == nil {
		return nil, errors.New("database not configured")
	}

	query := r.db.WithContext(ctx).Model(&entity.IntegrationAPIKey{})
	if environment != "" {
		query = query.Where("environment = ?", environment)
	}

	var records []entity.IntegrationAPIKey
	if err := query.Order("environment ASC").Order("name ASC").Find(&records).Error; err != nil {
		return nil, err
	}

	return records, nil
}

func (r *repository) Revoke(ctx context.Context, environment, prefix string, revokedAt time.Time) error {
	if r.db == nil {
		return errors.New("database not configured")
	}

	updates := map[string]any{
		"status":     entity.IntegrationAPIKeyStatusRevoked,
		"revoked_at": revokedAt,
		"updated_at": revokedAt,
	}

	result := r.db.WithContext(ctx).
		Model(&entity.IntegrationAPIKey{}).
		Where("environment = ?", environment).
		Where("key_prefix = ?", prefix).
		Updates(updates)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}
	return nil
}

func (r *repository) TouchLastUsed(ctx context.Context, id uint, usedAt time.Time, usedFrom string) error {
	if r.db == nil {
		return errors.New("database not configured")
	}

	return r.db.WithContext(ctx).
		Model(&entity.IntegrationAPIKey{}).
		Where("id = ?", id).
		Updates(map[string]any{
			"last_used_at":   usedAt,
			"last_used_from": usedFrom,
			"updated_at":     usedAt,
		}).Error
}
