import os
import sys
from datetime import datetime
from unittest.mock import MagicMock, patch

import polars as pl
import pytest

sys.path.insert(0, os.path.abspath("../../../.."))

from litellm.integrations.cloudzero.transform import CBFTransformer
from litellm.types.integrations.cloudzero import CBFRecord


class TestCBFTransformer:
    """Test suite for CBFTransformer class."""

    def test_init(self):
        """Test CBFTransformer initialization."""
        transformer = CBFTransformer()
        assert hasattr(transformer, 'czrn_generator')
        assert transformer.czrn_generator is not None

    def test_transform_empty_dataframe(self):
        """Test transform method with empty DataFrame."""
        transformer = CBFTransformer()
        empty_df = pl.DataFrame()
        
        result = transformer.transform(empty_df)
        
        assert result.is_empty()
        assert isinstance(result, pl.DataFrame)

    def test_transform_with_zero_successful_requests(self):
        """Test transform method filters out records with zero successful_requests."""
        transformer = CBFTransformer()
        data = pl.DataFrame({
            'date': ['2025-01-19'],
            'successful_requests': [0],
            'spend': [10.0],
            'entity_id': ['test_entity'],
            'model': ['gpt-4']
        })
        
        result = transformer.transform(data)
        
        assert result.is_empty()

    def test_transform_with_valid_data(self):
        """Test transform method with valid data."""
        transformer = CBFTransformer()
        with patch.object(transformer, '_create_cbf_record') as mock_create:
            mock_create.return_value = CBFRecord({'test': 'data'})
            
            data = pl.DataFrame({
                'date': ['2025-01-19'],
                'successful_requests': [5],
                'spend': [10.0],
                'entity_id': ['test_entity'],
                'model': ['gpt-4']
            })
            
            result = transformer.transform(data)
            
            assert len(result) == 1
            mock_create.assert_called_once()

    def test_transform_handles_czrn_generation_failures(self):
        """Test transform method handles CZRN generation failures gracefully."""
        transformer = CBFTransformer()
        with patch.object(transformer, '_create_cbf_record') as mock_create:
            mock_create.side_effect = Exception("CZRN generation failed")
            
            data = pl.DataFrame({
                'date': ['2025-01-19'],
                'successful_requests': [5],
                'spend': [10.0],
                'entity_id': ['test_entity'],
                'model': ['gpt-4']
            })
            
            result = transformer.transform(data)
            
            assert result.is_empty()

    def test_create_cbf_record(self):
        """Test _create_cbf_record method with valid row data."""
        transformer = CBFTransformer()
        with patch.object(transformer.czrn_generator, 'create_from_litellm_data') as mock_czrn, \
             patch.object(transformer.czrn_generator, 'extract_components') as mock_extract:
            
            mock_czrn.return_value = 'test-czrn'
            mock_extract.return_value = ('service', 'provider', 'region', 'account', 'resource', 'local_id')
            
            row = {
                'date': '2025-01-19',
                'spend': 10.5,
                'prompt_tokens': 100,
                'completion_tokens': 50,
                'entity_id': 'test_entity',
                'model': 'gpt-4',
                'entity_type': 'user',
                'model_group': 'openai',
                'custom_llm_provider': 'openai',
                'api_key': 'sk-test123',
                'api_requests': 5,
                'successful_requests': 5,
                'failed_requests': 0
            }
            
            result = transformer._create_cbf_record(row)
            
            assert isinstance(result, CBFRecord)
            assert result['cost/cost'] == 10.5
            assert result['usage/amount'] == 150  # 100 + 50
            assert result['usage/units'] == 'tokens'
            assert result['resource/id'] == 'test-czrn'

    def test_create_cbf_record_adds_user_email_tag(self):
        """Test that user_email field is emitted as a resource tag when present."""
        transformer = CBFTransformer()
        with patch.object(transformer.czrn_generator, 'create_from_litellm_data') as mock_czrn, \
             patch.object(transformer.czrn_generator, 'extract_components') as mock_extract:

            mock_czrn.return_value = 'test-czrn'
            mock_extract.return_value = ('service', 'provider', 'region', 'account', 'resource', 'local_id')

            row = {
                'date': '2025-01-19',
                'spend': 1.0,
                'prompt_tokens': 10,
                'completion_tokens': 5,
                'model': 'gpt-4',
                'api_key': 'sk-useremail',
                'team_id': 'team-123',
                'team_alias': 'Dev Team',
                'user_email': 'user@example.com'
            }

            result = transformer._create_cbf_record(row)

            assert result['resource/tag:user_email'] == 'user@example.com'

    def test_create_cbf_record_omits_empty_user_email(self):
        """Test that empty user_email values are not added as resource tags."""
        transformer = CBFTransformer()
        with patch.object(transformer.czrn_generator, 'create_from_litellm_data') as mock_czrn, \
             patch.object(transformer.czrn_generator, 'extract_components') as mock_extract:

            mock_czrn.return_value = 'test-czrn'
            mock_extract.return_value = ('service', 'provider', 'region', 'account', 'resource', 'local_id')

            row = {
                'date': '2025-01-19',
                'spend': 1.0,
                'prompt_tokens': 10,
                'completion_tokens': 5,
                'model': 'gpt-4',
                'api_key': 'sk-useremail',
                'team_id': 'team-123',
                'team_alias': 'Dev Team',
                'user_email': None
            }

            result = transformer._create_cbf_record(row)

            assert 'resource/tag:user_email' not in result

    def test_create_cbf_record_minimal_data(self):
        """Test _create_cbf_record method with minimal row data."""
        transformer = CBFTransformer()
        with patch.object(transformer.czrn_generator, 'create_from_litellm_data') as mock_czrn, \
             patch.object(transformer.czrn_generator, 'extract_components') as mock_extract:
            
            mock_czrn.return_value = 'test-czrn'
            mock_extract.return_value = ('service', 'provider', 'region', 'account', 'resource', 'local_id')
            
            row = {
                'date': '2025-01-19',
                'spend': 0.0
            }
            
            result = transformer._create_cbf_record(row)
            
            assert isinstance(result, CBFRecord)
            assert result['cost/cost'] == 0.0
            assert result['usage/amount'] == 0  # no tokens
            assert result['usage/units'] == 'tokens'

    def test_parse_date_with_valid_string(self):
        """Test _parse_date method with valid date string."""
        transformer = CBFTransformer()
        
        result = transformer._parse_date('2025-01-19')
        
        assert isinstance(result, datetime)
        assert result.year == 2025
        assert result.month == 1
        assert result.day == 19

    def test_parse_date_with_datetime_object(self):
        """Test _parse_date method with datetime object."""
        transformer = CBFTransformer()
        dt = datetime(2025, 1, 19)
        
        result = transformer._parse_date(dt)
        
        assert result == dt

    def test_parse_date_with_none(self):
        """Test _parse_date method with None."""
        transformer = CBFTransformer()
        
        result = transformer._parse_date(None)
        
        assert result is None

    def test_parse_date_with_invalid_string(self):
        """Test _parse_date method with invalid date string."""
        transformer = CBFTransformer()
        
        result = transformer._parse_date('invalid-date')
        
        assert result is None

    def test_parse_date_with_iso_format(self):
        """Test _parse_date method with ISO format string."""
        transformer = CBFTransformer()
        
        result = transformer._parse_date('2025-01-19T10:30:00Z')
        
        assert isinstance(result, datetime)
        assert result.year == 2025 
