package service

import (
	"context"
	"fmt"

	"apskel-pos-be/internal/models"
	"apskel-pos-be/internal/processor"

	"github.com/google/uuid"
)

type AnalyticsService interface {
	GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error)
	GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error)
	GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error)
	GetProductAnalyticsPerCategory(ctx context.Context, req *models.ProductAnalyticsPerCategoryRequest) (*models.ProductAnalyticsPerCategoryResponse, error)
	GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error)
	GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error)
}

type AnalyticsServiceImpl struct {
	analyticsProcessor processor.AnalyticsProcessor
}

func NewAnalyticsServiceImpl(analyticsProcessor processor.AnalyticsProcessor) *AnalyticsServiceImpl {
	return &AnalyticsServiceImpl{
		analyticsProcessor: analyticsProcessor,
	}
}

func (s *AnalyticsServiceImpl) GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error) {
	if err := s.validatePaymentMethodAnalyticsRequest(req); err != nil {
		return nil, fmt.Errorf("validation error: %w", err)
	}

	response, err := s.analyticsProcessor.GetPaymentMethodAnalytics(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to get payment method analytics: %w", err)
	}

	return response, nil
}

func (s *AnalyticsServiceImpl) GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error) {
	// Validate request
	if err := s.validateSalesAnalyticsRequest(req); err != nil {
		return nil, fmt.Errorf("validation error: %w", err)
	}

	// Process analytics request
	response, err := s.analyticsProcessor.GetSalesAnalytics(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to get sales analytics: %w", err)
	}

	return response, nil
}

func (s *AnalyticsServiceImpl) GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error) {
	// Validate request
	if err := s.validateProductAnalyticsRequest(req); err != nil {
		return nil, fmt.Errorf("validation error: %w", err)
	}

	// Process analytics request
	response, err := s.analyticsProcessor.GetProductAnalytics(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to get product analytics: %w", err)
	}

	return response, nil
}

func (s *AnalyticsServiceImpl) GetProductAnalyticsPerCategory(ctx context.Context, req *models.ProductAnalyticsPerCategoryRequest) (*models.ProductAnalyticsPerCategoryResponse, error) {
	// Validate request
	if err := s.validateProductAnalyticsPerCategoryRequest(req); err != nil {
		return nil, fmt.Errorf("validation error: %w", err)
	}

	// Process analytics request
	response, err := s.analyticsProcessor.GetProductAnalyticsPerCategory(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to get product analytics per category: %w", err)
	}

	return response, nil
}

func (s *AnalyticsServiceImpl) GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error) {
	// Validate request
	if err := s.validateDashboardAnalyticsRequest(req); err != nil {
		return nil, fmt.Errorf("validation error: %w", err)
	}

	// Process analytics request
	response, err := s.analyticsProcessor.GetDashboardAnalytics(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to get dashboard analytics: %w", err)
	}

	return response, nil
}

// Validation methods
func (s *AnalyticsServiceImpl) validatePaymentMethodAnalyticsRequest(req *models.PaymentMethodAnalyticsRequest) error {
	if req.OrganizationID == uuid.Nil {
		return fmt.Errorf("organization ID is required")
	}

	if req.DateFrom.IsZero() {
		return fmt.Errorf("date_from is required")
	}

	if req.DateTo.IsZero() {
		return fmt.Errorf("date_to is required")
	}

	if req.DateFrom.After(req.DateTo) {
		return fmt.Errorf("date_from cannot be after date_to")
	}

	if req.GroupBy != "" {
		validGroupBy := map[string]bool{
			"day":   true,
			"hour":  true,
			"week":  true,
			"month": true,
		}
		if !validGroupBy[req.GroupBy] {
			return fmt.Errorf("invalid group_by value: %s", req.GroupBy)
		}
	}

	return nil
}

func (s *AnalyticsServiceImpl) validateSalesAnalyticsRequest(req *models.SalesAnalyticsRequest) error {
	if req.OrganizationID == uuid.Nil {
		return fmt.Errorf("organization ID is required")
	}

	if req.DateFrom.IsZero() {
		return fmt.Errorf("date_from is required")
	}

	if req.DateTo.IsZero() {
		return fmt.Errorf("date_to is required")
	}

	if req.DateFrom.After(req.DateTo) {
		return fmt.Errorf("date_from cannot be after date_to")
	}

	// Validate groupBy if provided
	if req.GroupBy != "" {
		validGroupBy := map[string]bool{
			"day":   true,
			"hour":  true,
			"week":  true,
			"month": true,
		}
		if !validGroupBy[req.GroupBy] {
			return fmt.Errorf("invalid group_by value: %s", req.GroupBy)
		}
	}

	return nil
}

func (s *AnalyticsServiceImpl) validateProductAnalyticsRequest(req *models.ProductAnalyticsRequest) error {
	if req.OrganizationID == uuid.Nil {
		return fmt.Errorf("organization ID is required")
	}

	if req.DateFrom.IsZero() {
		return fmt.Errorf("date_from is required")
	}

	if req.DateTo.IsZero() {
		return fmt.Errorf("date_to is required")
	}

	if req.DateFrom.After(req.DateTo) {
		return fmt.Errorf("date_from cannot be after date_to")
	}

	if req.Limit < 1 || req.Limit > 100 {
		return fmt.Errorf("limit must be between 1 and 100")
	}

	return nil
}

func (s *AnalyticsServiceImpl) validateProductAnalyticsPerCategoryRequest(req *models.ProductAnalyticsPerCategoryRequest) error {
	if req.OrganizationID == uuid.Nil {
		return fmt.Errorf("organization ID is required")
	}

	if req.DateFrom.IsZero() {
		return fmt.Errorf("date_from is required")
	}

	if req.DateTo.IsZero() {
		return fmt.Errorf("date_to is required")
	}

	if req.DateFrom.After(req.DateTo) {
		return fmt.Errorf("date_from cannot be after date_to")
	}

	return nil
}

func (s *AnalyticsServiceImpl) validateDashboardAnalyticsRequest(req *models.DashboardAnalyticsRequest) error {
	if req.OrganizationID == uuid.Nil {
		return fmt.Errorf("organization ID is required")
	}

	if req.DateFrom.IsZero() {
		return fmt.Errorf("date_from is required")
	}

	if req.DateTo.IsZero() {
		return fmt.Errorf("date_to is required")
	}

	if req.DateFrom.After(req.DateTo) {
		return fmt.Errorf("date_from cannot be after date_to")
	}

	return nil
}

func (s *AnalyticsServiceImpl) GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error) {
	// Validate request
	if err := s.validateProfitLossAnalyticsRequest(req); err != nil {
		return nil, fmt.Errorf("validation error: %w", err)
	}

	// Call processor
	response, err := s.analyticsProcessor.GetProfitLossAnalytics(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to get profit/loss analytics: %w", err)
	}

	return response, nil
}

func (s *AnalyticsServiceImpl) validateProfitLossAnalyticsRequest(req *models.ProfitLossAnalyticsRequest) error {
	if req == nil {
		return fmt.Errorf("request cannot be nil")
	}

	if req.OrganizationID == uuid.Nil {
		return fmt.Errorf("organization_id is required")
	}

	if req.DateFrom.IsZero() {
		return fmt.Errorf("date_from is required")
	}

	if req.DateTo.IsZero() {
		return fmt.Errorf("date_to is required")
	}

	if req.DateFrom.After(req.DateTo) {
		return fmt.Errorf("date_from cannot be after date_to")
	}

	if req.GroupBy != "" && req.GroupBy != "hour" && req.GroupBy != "day" && req.GroupBy != "week" && req.GroupBy != "month" {
		return fmt.Errorf("invalid group_by value, must be one of: hour, day, week, month")
	}

	return nil
}
