package services

import (
	"context"
	"fmt"

	"go.uber.org/zap"

	"github.com/kms/api-key-service/internal/domain"
	"github.com/kms/api-key-service/internal/repository"
)

// applicationService implements the ApplicationService interface
type applicationService struct {
	appRepo repository.ApplicationRepository
	logger  *zap.Logger
}

// NewApplicationService creates a new application service
func NewApplicationService(appRepo repository.ApplicationRepository, logger *zap.Logger) ApplicationService {
	return &applicationService{
		appRepo: appRepo,
		logger:  logger,
	}
}

// Create creates a new application
func (s *applicationService) Create(ctx context.Context, req *domain.CreateApplicationRequest, userID string) (*domain.Application, error) {
	s.logger.Info("Creating application", zap.String("app_id", req.AppID), zap.String("user_id", userID))

	// TODO: Add permission validation
	// TODO: Add input validation using validator

	app := &domain.Application{
		AppID:                req.AppID,
		AppLink:              req.AppLink,
		Type:                 req.Type,
		CallbackURL:          req.CallbackURL,
		HMACKey:              generateHMACKey(), // TODO: Use proper key generation
		TokenRenewalDuration: req.TokenRenewalDuration,
		MaxTokenDuration:     req.MaxTokenDuration,
		Owner:                req.Owner,
	}

	if err := s.appRepo.Create(ctx, app); err != nil {
		s.logger.Error("Failed to create application", zap.Error(err), zap.String("app_id", req.AppID))
		return nil, fmt.Errorf("failed to create application: %w", err)
	}

	s.logger.Info("Application created successfully", zap.String("app_id", app.AppID))
	return app, nil
}

// GetByID retrieves an application by its ID
func (s *applicationService) GetByID(ctx context.Context, appID string) (*domain.Application, error) {
	s.logger.Debug("Getting application by ID", zap.String("app_id", appID))

	app, err := s.appRepo.GetByID(ctx, appID)
	if err != nil {
		s.logger.Error("Failed to get application", zap.Error(err), zap.String("app_id", appID))
		return nil, fmt.Errorf("failed to get application: %w", err)
	}

	return app, nil
}

// List retrieves applications with pagination
func (s *applicationService) List(ctx context.Context, limit, offset int) ([]*domain.Application, error) {
	s.logger.Debug("Listing applications", zap.Int("limit", limit), zap.Int("offset", offset))

	if limit <= 0 {
		limit = 50 // Default limit
	}
	if limit > 100 {
		limit = 100 // Max limit
	}

	apps, err := s.appRepo.List(ctx, limit, offset)
	if err != nil {
		s.logger.Error("Failed to list applications", zap.Error(err))
		return nil, fmt.Errorf("failed to list applications: %w", err)
	}

	s.logger.Debug("Listed applications", zap.Int("count", len(apps)))
	return apps, nil
}

// Update updates an existing application
func (s *applicationService) Update(ctx context.Context, appID string, updates *domain.UpdateApplicationRequest, userID string) (*domain.Application, error) {
	s.logger.Info("Updating application", zap.String("app_id", appID), zap.String("user_id", userID))

	// TODO: Add permission validation
	// TODO: Add input validation

	app, err := s.appRepo.Update(ctx, appID, updates)
	if err != nil {
		s.logger.Error("Failed to update application", zap.Error(err), zap.String("app_id", appID))
		return nil, fmt.Errorf("failed to update application: %w", err)
	}

	s.logger.Info("Application updated successfully", zap.String("app_id", appID))
	return app, nil
}

// Delete deletes an application
func (s *applicationService) Delete(ctx context.Context, appID string, userID string) error {
	s.logger.Info("Deleting application", zap.String("app_id", appID), zap.String("user_id", userID))

	// TODO: Add permission validation
	// TODO: Check for existing tokens and handle appropriately

	if err := s.appRepo.Delete(ctx, appID); err != nil {
		s.logger.Error("Failed to delete application", zap.Error(err), zap.String("app_id", appID))
		return fmt.Errorf("failed to delete application: %w", err)
	}

	s.logger.Info("Application deleted successfully", zap.String("app_id", appID))
	return nil
}

// generateHMACKey generates a secure HMAC key
// TODO: Replace with proper cryptographic key generation
func generateHMACKey() string {
	// This is a placeholder - should use proper crypto/rand
	return "generated-hmac-key-placeholder"
}
