import os
import sys
import pytest

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))

from services.dynamic_reward_service import DynamicRewardService

@pytest.fixture
def dynamic_reward_service():
    return DynamicRewardService

# TESTS FOR NORMALIZE_REACH

def test_normalize_reach_max(dynamic_reward_service):
    assert dynamic_reward_service.normalize_reach(dynamic_reward_service.MAX_REACH_THRESHOLD) == 100.0

def test_normalize_reach_min(dynamic_reward_service):
    assert dynamic_reward_service.normalize_reach(0) == 0.0

def test_normalize_reach_mid(dynamic_reward_service):
    assert dynamic_reward_service.normalize_reach(dynamic_reward_service.MAX_REACH_THRESHOLD / 2) == 50.0


# TESTS FOR NORMALIZE_CONTENT_SCORE

def test_normalize_content_score_max(dynamic_reward_service):
    assert dynamic_reward_service.normalize_content_score(100) == 100.0

def test_normalize_content_score_min(dynamic_reward_service):
    assert dynamic_reward_service.normalize_content_score(0) == 0.0

def test_normalize_content_score_mid(dynamic_reward_service):
    assert dynamic_reward_service.normalize_content_score(80) == 50.0

def test_normalize_content_score_below_min(dynamic_reward_service):
    assert dynamic_reward_service.normalize_content_score(30) == 0.0


# TESTS FOR CALCULATE_DYNAMIC_COMPENSATION_AMOUNT
    
def test_min_compensation_boundary(dynamic_reward_service):
    min_compensation = 5
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=min_compensation, 
        max_compensation=20, 
        content_score=dynamic_reward_service.MIN_CONTENT_SCORE, 
        reach=0
    ) == min_compensation

def test_min_compensation_boundary_below(dynamic_reward_service):
    min_compensation = 5
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=min_compensation, 
        max_compensation=20, 
        content_score=dynamic_reward_service.MIN_CONTENT_SCORE - 20, # try a score below passing
        reach=0
    ) == min_compensation

def test_max_compensation_boundary(dynamic_reward_service):
    max_compensation = 10   
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=2,
        max_compensation=max_compensation, 
        content_score=100, 
        reach=dynamic_reward_service.MAX_REACH_THRESHOLD
    ) == max_compensation

def test_max_compensation_boundary_above_reach(dynamic_reward_service):
    max_compensation = 10   
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=2,
        max_compensation=max_compensation, 
        content_score=100, 
        reach=dynamic_reward_service.MAX_REACH_THRESHOLD + 1000 # reach above max threshold
    ) == max_compensation

def test_max_compensation_boundary_above_score(dynamic_reward_service):
    max_compensation = 10   
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=2,
        max_compensation=max_compensation, 
        content_score=101, # impossibly high score 
        reach=dynamic_reward_service.MAX_REACH_THRESHOLD
    ) == max_compensation

def test_mid_compensation(dynamic_reward_service):
    compensation = dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=20, 
        content_score=80, 
        reach=1000
    )
    # convert to 3 decimal places to avoid floating point errors
    assert round(compensation, 3) == 13.167

def test_mid_compensation_2(dynamic_reward_service):
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=20, 
        content_score=dynamic_reward_service.MIN_CONTENT_SCORE, 
        reach=7500
    ) == 15

def test_mid_compensation_3(dynamic_reward_service):
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=20, 
        content_score=dynamic_reward_service.MAX_CONTENT_SCORE, 
        reach=750
    ) == 15.5

def test_max_compensation_boundary_with_max_multiplier(dynamic_reward_service):
    max_compensation = 20
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=max_compensation, 
        content_score=dynamic_reward_service.MAX_CONTENT_SCORE, 
        reach=dynamic_reward_service.MAX_REACH_THRESHOLD,
        multiplier=1.0
    ) == max_compensation

def test_compensation_with_multiplier(dynamic_reward_service):
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=20, 
        content_score=dynamic_reward_service.MAX_CONTENT_SCORE, 
        reach=750,
        multiplier=.75
    ) == 11.625

def test_compensation_with_multiplier_2(dynamic_reward_service):
    min_compensation = 10
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=min_compensation,
        max_compensation=20, 
        content_score=dynamic_reward_service.MIN_CONTENT_SCORE, 
        reach=750,
        multiplier=.9
    ) == min_compensation

def test_compensation_ignore_reach_max(dynamic_reward_service):
    max_compensation = 30
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=5,
        max_compensation=max_compensation,
        content_score=dynamic_reward_service.MAX_CONTENT_SCORE, 
        reach=2500,
        ignore_reach=True
    ) == max_compensation

def test_compensation_ignore_reach_min(dynamic_reward_service):
    min_compensation = 5
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=min_compensation, 
        max_compensation=20, 
        content_score=dynamic_reward_service.MIN_CONTENT_SCORE, 
        reach=750,
        ignore_reach=True
    ) == min_compensation

def test_compensation_ignore_reach_mid(dynamic_reward_service):
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=20, 
        content_score=dynamic_reward_service.MAX_CONTENT_SCORE - 20, 
        reach=750,
        ignore_reach=True
    ) == 15

def test_compensation_ignore_reach_with_multiplier(dynamic_reward_service):
    assert dynamic_reward_service.calculate_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=20, 
        content_score=dynamic_reward_service.MAX_CONTENT_SCORE, 
        reach=750,
        ignore_reach=True,
        multiplier=.8
    ) == 16

# TESTS FOR CALCULATE_TAILORED_COMPENSATION_BOUNDS
    
def test_tailored_compensation_bounds_max(dynamic_reward_service):
    min_compensation, max_compensation = dynamic_reward_service.calculate_tailored_compensation_bounds(
        min_compensation=20,
        max_compensation=50, 
        reach=dynamic_reward_service.MAX_REACH_THRESHOLD
    ) 
    assert min_compensation == 35
    assert max_compensation == 50

def test_tailored_compensation_bounds_min(dynamic_reward_service):
    min_compensation, max_compensation = dynamic_reward_service.calculate_tailored_compensation_bounds(
        min_compensation=10,
        max_compensation=20, 
        reach=0
    )
    assert min_compensation == 10
    assert max_compensation == 15

def test_tailored_compensation_bounds_mid(dynamic_reward_service):
    min_compensation, max_compensation = dynamic_reward_service.calculate_tailored_compensation_bounds(
        min_compensation=10,
        max_compensation=20, 
        reach=750
    )
    assert min_compensation == 10
    assert max_compensation == 16

def test_tailored_compensation_bounds_ignore_reach(dynamic_reward_service):
    min_compensation, max_compensation = dynamic_reward_service.calculate_tailored_compensation_bounds(
        min_compensation=10,
        max_compensation=20, 
        reach=750,
        ignore_reach=True
    )
    assert min_compensation == 10
    assert max_compensation == 20

def test_tailored_compensation_bounds_with_multiplier(dynamic_reward_service):
    min_compensation, max_compensation = dynamic_reward_service.calculate_tailored_compensation_bounds(
        min_compensation=10,
        max_compensation=20, 
        reach=750,
        multiplier=.9
    )
    assert min_compensation == 10
    assert max_compensation == 14

def test_tailored_compensation_bounds_ignore_reach_with_multiplier(dynamic_reward_service):
    min_compensation, max_compensation = dynamic_reward_service.calculate_tailored_compensation_bounds(
        min_compensation=10,
        max_compensation=20, 
        reach=750,
        ignore_reach=True,
        multiplier=.9
    )
    assert min_compensation == 10
    assert max_compensation == 18


# TESTS FOR CALCULATE_ROUNDED_DYNAMIC_COMPENSATION_AMOUNT
def test_rounded_compensation_amount(dynamic_reward_service):
    assert dynamic_reward_service.calculate_rounded_dynamic_compensation_amount(
        min_compensation=10,
        max_compensation=20, 
        content_score=dynamic_reward_service.MAX_CONTENT_SCORE, 
        reach=750,
    ) == 15.50
    

def test_rounded_compensation_amount_2(dynamic_reward_service):
    assert dynamic_reward_service.calculate_rounded_dynamic_compensation_amount(
       min_compensation=10,
        max_compensation=20, 
        content_score=80, 
        reach=1000
    ) == 13

