package services

import (
	"context"
	"fmt"
	"time"

	"payment/internal/models"

	"github.com/google/uuid"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

// PackageService handles internet package operations
type PackageService struct {
	db *gorm.DB
}

// NewPackageService creates a new package service
func NewPackageService(db *gorm.DB) *PackageService {
	return &PackageService{
		db: db,
	}
}

// CreatePackageRequest represents a request to create an internet package
type CreatePackageRequest struct {
	ClientID    *uuid.UUID `json:"client_id,omitempty"` // Set from auth context, not required in request body
	Name        string     `json:"name" binding:"required"`
	Description string     `json:"description"`
	Amount      float64    `json:"amount" binding:"required"`
	Currency    string     `json:"currency"`
	Speed       string     `json:"speed"`
	Duration    string     `json:"duration"`
}

// UpdatePackageRequest represents a request to update an internet package
type UpdatePackageRequest struct {
	Name        *string  `json:"name"`
	Description *string  `json:"description"`
	Amount      *float64 `json:"amount"`
	Currency    *string  `json:"currency"`
	Speed       *string  `json:"speed"`
	Duration    *string  `json:"duration"`
	IsActive    *bool    `json:"is_active"`
}

// PackageResponse represents a package response
type PackageResponse struct {
	ID          uuid.UUID `json:"id"`
	ClientID    uuid.UUID `json:"client_id"`
	Name        string    `json:"name"`
	Description string    `json:"description"`
	Amount      float64   `json:"amount"`
	Currency    string    `json:"currency"`
	Speed       string    `json:"speed"`
	Duration    string    `json:"duration"`
	IsActive    bool      `json:"is_active"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

// CreatePackage creates a new internet package
func (s *PackageService) CreatePackage(ctx context.Context, req *CreatePackageRequest) (*PackageResponse, error) {
	// Validate client exists
	var client models.Client
	if err := s.db.Where("id = ? AND is_active = true", *req.ClientID).First(&client).Error; err != nil {
		return nil, fmt.Errorf("client not found or inactive: %w", err)
	}

	// Set default currency if not provided
	currency := req.Currency
	if currency == "" {
		currency = "KES"
	}

	packageInfo := &models.InternetPackage{
		ClientID:    *req.ClientID,
		Name:        req.Name,
		Description: req.Description,
		Amount:      req.Amount,
		Currency:    currency,
		Speed:       req.Speed,
		Duration:    req.Duration,
		IsActive:    true,
	}

	if err := s.db.Create(packageInfo).Error; err != nil {
		return nil, fmt.Errorf("failed to create package: %w", err)
	}

	logrus.WithFields(logrus.Fields{
		"package_id": packageInfo.ID,
		"client_id":  *req.ClientID,
		"name":       req.Name,
		"amount":     req.Amount,
	}).Info("Internet package created")

	return &PackageResponse{
		ID:          packageInfo.ID,
		ClientID:    packageInfo.ClientID,
		Name:        packageInfo.Name,
		Description: packageInfo.Description,
		Amount:      packageInfo.Amount,
		Currency:    packageInfo.Currency,
		Speed:       packageInfo.Speed,
		Duration:    packageInfo.Duration,
		IsActive:    packageInfo.IsActive,
		CreatedAt:   packageInfo.CreatedAt,
		UpdatedAt:   packageInfo.UpdatedAt,
	}, nil
}

// GetPackages retrieves packages for a client with pagination support
func (s *PackageService) GetPackages(ctx context.Context, clientID uuid.UUID, activeOnly bool, limit, offset int) ([]*PackageResponse, int64, error) {
	var packages []models.InternetPackage
	var totalCount int64
	
	query := s.db.Model(&models.InternetPackage{}).Where("client_id = ?", clientID)

	if activeOnly {
		query = query.Where("is_active = ?", true)
	}

	// Count total records
	if err := query.Count(&totalCount).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to count packages: %w", err)
	}

	// Apply pagination
	if limit > 0 {
		query = query.Limit(limit)
	}
	if offset > 0 {
		query = query.Offset(offset)
	}

	if err := query.Order("created_at DESC").Find(&packages).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to fetch packages: %w", err)
	}

	var responses []*PackageResponse
	for _, pkg := range packages {
		responses = append(responses, &PackageResponse{
			ID:          pkg.ID,
			ClientID:    pkg.ClientID,
			Name:        pkg.Name,
			Description: pkg.Description,
			Amount:      pkg.Amount,
			Currency:    pkg.Currency,
			Speed:       pkg.Speed,
			Duration:    pkg.Duration,
			IsActive:    pkg.IsActive,
			CreatedAt:   pkg.CreatedAt,
			UpdatedAt:   pkg.UpdatedAt,
		})
	}

	return responses, totalCount, nil
}

// GetPackage retrieves a specific package
func (s *PackageService) GetPackage(ctx context.Context, clientID, packageID uuid.UUID) (*PackageResponse, error) {
	var packageInfo models.InternetPackage
	if err := s.db.Where("id = ? AND client_id = ?", packageID, clientID).First(&packageInfo).Error; err != nil {
		return nil, fmt.Errorf("package not found: %w", err)
	}

	return &PackageResponse{
		ID:          packageInfo.ID,
		ClientID:    packageInfo.ClientID,
		Name:        packageInfo.Name,
		Description: packageInfo.Description,
		Amount:      packageInfo.Amount,
		Currency:    packageInfo.Currency,
		Speed:       packageInfo.Speed,
		Duration:    packageInfo.Duration,
		IsActive:    packageInfo.IsActive,
		CreatedAt:   packageInfo.CreatedAt,
		UpdatedAt:   packageInfo.UpdatedAt,
	}, nil
}

// UpdatePackage updates an internet package
func (s *PackageService) UpdatePackage(ctx context.Context, clientID, packageID uuid.UUID, req *UpdatePackageRequest) (*PackageResponse, error) {
	var packageInfo models.InternetPackage
	if err := s.db.Where("id = ? AND client_id = ?", packageID, clientID).First(&packageInfo).Error; err != nil {
		return nil, fmt.Errorf("package not found: %w", err)
	}

	// Update fields if provided
	updates := make(map[string]interface{})
	if req.Name != nil {
		updates["name"] = *req.Name
	}
	if req.Description != nil {
		updates["description"] = *req.Description
	}
	if req.Amount != nil {
		updates["amount"] = *req.Amount
	}
	if req.Currency != nil {
		updates["currency"] = *req.Currency
	}
	if req.Speed != nil {
		updates["speed"] = *req.Speed
	}
	if req.Duration != nil {
		updates["duration"] = *req.Duration
	}
	if req.IsActive != nil {
		updates["is_active"] = *req.IsActive
	}

	if err := s.db.Model(&packageInfo).Updates(updates).Error; err != nil {
		return nil, fmt.Errorf("failed to update package: %w", err)
	}

	// Refresh the package data
	if err := s.db.Where("id = ?", packageID).First(&packageInfo).Error; err != nil {
		return nil, fmt.Errorf("failed to refresh package data: %w", err)
	}

	logrus.WithFields(logrus.Fields{
		"package_id": packageID,
		"client_id":  clientID,
	}).Info("Internet package updated")

	return &PackageResponse{
		ID:          packageInfo.ID,
		ClientID:    packageInfo.ClientID,
		Name:        packageInfo.Name,
		Description: packageInfo.Description,
		Amount:      packageInfo.Amount,
		Currency:    packageInfo.Currency,
		Speed:       packageInfo.Speed,
		Duration:    packageInfo.Duration,
		IsActive:    packageInfo.IsActive,
		CreatedAt:   packageInfo.CreatedAt,
		UpdatedAt:   packageInfo.UpdatedAt,
	}, nil
}

// DeletePackage soft deletes an internet package
func (s *PackageService) DeletePackage(ctx context.Context, clientID, packageID uuid.UUID) error {
	var packageInfo models.InternetPackage
	if err := s.db.Where("id = ? AND client_id = ?", packageID, clientID).First(&packageInfo).Error; err != nil {
		return fmt.Errorf("package not found: %w", err)
	}

	if err := s.db.Delete(&packageInfo).Error; err != nil {
		return fmt.Errorf("failed to delete package: %w", err)
	}

	logrus.WithFields(logrus.Fields{
		"package_id": packageID,
		"client_id":  clientID,
	}).Info("Internet package deleted")

	return nil
}
