"""Test core functionality that actually exists in the RateRight app"""
import pytest
from datetime import datetime, date, timedelta, time
from app import create_app
from app.extensions import db
from app.models import User, Job, Application, Contract, Category
from app.models.message import Message, MessageStatus
from app.models.notification import Notification, NotificationPreference, NotificationType
from app.models.gamification import PointActivity, Achievement
from app.models.safety import Review


@pytest.fixture
def app():
    """Create and configure test app"""
    app = create_app()
    app.config.update({
        'TESTING': True,
        'SQLALCHEMY_DATABASE_URI': 'sqlite:///:memory:',
        'WTF_CSRF_ENABLED': False,
        'SECRET_KEY': 'test-secret-key'
    })
    
    with app.app_context():
        db.create_all()
        yield app
        db.session.remove()
        db.drop_all()


@pytest.fixture
def sample_category(app):
    """Create a test category"""
    category = Category(
        name='General Construction',
        description='General construction work',
        whs_risk_level='medium'
    )
    db.session.add(category)
    db.session.commit()
    return category


@pytest.fixture
def sample_user(app):
    """Create a test user"""
    user = User(
        email='test@example.com',
        first_name='Test',
        last_name='User',
        role='worker',
        phone_number='0400000001',
        location='Sydney, NSW',
        abn_number='12345678901',  # Required for Australian users
        is_active=True,
        privacy_consent=True,
        terms_accepted=True,
        terms_accepted_date=datetime.utcnow()
    )
    user.set_password('password123')
    db.session.add(user)
    db.session.commit()
    return user


class TestCoreModels:
    """Test that basic models work as expected"""
    
    def test_user_creation_and_authentication(self, app):
        """Test user model basic functionality"""
        with app.app_context():
            user = User(
                email='auth@test.com',
                first_name='Auth',
                last_name='Test',
                role='contractor',
                phone_number='0400000002',
                location='Melbourne, VIC',
                abn_number='98765432109',  # Required for Australian users
                is_active=True,
                privacy_consent=True,
                terms_accepted=True,
                terms_accepted_date=datetime.utcnow()
            )
            user.set_password('testpass')
            db.session.add(user)
            db.session.commit()
            
            # Test password checking
            assert user.check_password('testpass') is True
            assert user.check_password('wrongpass') is False
            
            # Test user retrieval
            found_user = User.query.filter_by(email='auth@test.com').first()
            assert found_user is not None
            assert found_user.first_name == 'Auth'
            assert found_user.role == 'contractor'
    
    def test_category_creation(self, app):
        """Test category model"""
        with app.app_context():
            category = Category(
                name='Plumbing',
                description='Plumbing work',
                whs_risk_level='high',
                insurance_requirements='$5M liability',
                license_required=True
            )
            db.session.add(category)
            db.session.commit()
            
            # Test retrieval
            found_category = Category.query.filter_by(name='Plumbing').first()
            assert found_category is not None
            assert found_category.whs_risk_level == 'high'
            assert found_category.license_required is True
            
            # Test insurance minimum calculation
            assert found_category.get_insurance_minimum() == 5000000
    
    def test_job_creation(self, app, sample_category, sample_user):
        """Test job posting"""
        with app.app_context():
            job = Job(
                title='Test Construction Job',
                description='Test job description',
                contractor_id=sample_user.id,
                category_id=sample_category.id,
                location='Sydney, NSW',
                budget_min=1000.00,
                budget_max=2000.00,
                status='open'
            )
            db.session.add(job)
            db.session.commit()
            
            # Test retrieval
            found_job = Job.query.filter_by(title='Test Construction Job').first()
            assert found_job is not None
            assert found_job.contractor_id == sample_user.id
            assert found_job.category_id == sample_category.id
            assert found_job.budget_min == 1000.00
    
    def test_application_workflow(self, app, sample_category, sample_user):
        """Test job application process"""
        with app.app_context():
            # Create another user to apply
            applicant = User(
                email='applicant@test.com',
                first_name='App',
                last_name='Licant',
                role='worker',
                phone_number='0400000003',
                location='Sydney, NSW',
                abn_number='11223344556',  # Required for Australian users
                is_active=True,
                privacy_consent=True,
                terms_accepted=True,
                terms_accepted_date=datetime.utcnow()
            )
            applicant.set_password('password')
            db.session.add(applicant)
            db.session.flush()
            
            # Create job
            job = Job(
                title='Apply Test Job',
                description='Job for application testing',
                contractor_id=sample_user.id,
                category_id=sample_category.id,
                location='Sydney, NSW',
                budget_min=1500.00,
                budget_max=2500.00,
                status='open'
            )
            db.session.add(job)
            db.session.flush()
            
            # Create application
            application = Application(
                job_id=job.id,
                worker_id=applicant.id,
                status='pending',
                proposed_rate=1800.00,
                cover_letter='I am interested in this job'
            )
            db.session.add(application)
            db.session.commit()
            
            # Test application retrieval
            found_app = Application.query.filter_by(job_id=job.id).first()
            assert found_app is not None
            assert found_app.worker_id == applicant.id
            assert found_app.proposed_rate == 1800.00
            assert found_app.status == 'pending'


class TestMessaging:
    """Test message functionality that exists"""
    
    def test_message_creation(self, app, sample_user):
        """Test basic message creation"""
        with app.app_context():
            # Create another user for messaging
            receiver = User(
                email='receiver@test.com',
                first_name='Rec',
                last_name='Eiver',
                role='contractor',
                phone_number='0400000004',
                location='Brisbane, QLD',
                abn_number='99887766554',  # Required for Australian users
                is_active=True,
                privacy_consent=True,
                terms_accepted=True,
                terms_accepted_date=datetime.utcnow()
            )
            receiver.set_password('password')
            db.session.add(receiver)
            db.session.flush()
            
            # Create message
            message = Message(
                sender_id=sample_user.id,
                receiver_id=receiver.id,
                text='Hello, this is a test message',
                status=MessageStatus.SENT
            )
            db.session.add(message)
            db.session.commit()
            
            # Test retrieval
            found_msg = Message.query.filter_by(sender_id=sample_user.id).first()
            assert found_msg is not None
            assert found_msg.text == 'Hello, this is a test message'
            assert found_msg.status == MessageStatus.SENT
            
            # Test message methods
            found_msg.mark_as_delivered()
            assert found_msg.status == MessageStatus.DELIVERED
            
            found_msg.mark_as_read()
            assert found_msg.is_read is True


class TestGamification:
    """Test gamification features that exist"""
    
    def test_point_activity_creation(self, app, sample_user):
        """Test point tracking"""
        with app.app_context():
            # Create point activity
            activity = PointActivity(
                user_id=sample_user.id,
                activity_type='job_completed',
                points_earned=100,
                description='Completed first job',
                base_points=100,
                bonus_multiplier=1.0
            )
            db.session.add(activity)
            db.session.commit()
            
            # Test retrieval
            found_activity = PointActivity.query.filter_by(user_id=sample_user.id).first()
            assert found_activity is not None
            assert found_activity.points_earned == 100
            assert found_activity.activity_type == 'job_completed'
    
    def test_user_gamification_methods(self, app, sample_user):
        """Test user gamification features"""
        with app.app_context():
            # Test initial state
            level = sample_user.get_gamification_level()
            assert level >= 1  # Should have a default level
            
            # Set some points and test level calculation
            sample_user.total_points = 500
            db.session.commit()
            
            level = sample_user.get_gamification_level()
            assert level > 1  # Should level up with points


class TestRatingSystem:
    """Test rating functionality that exists"""
    
    def test_review_creation(self, app, sample_user, sample_category):
        """Test review/rating creation"""
        with app.app_context():
            # Create contractor user
            contractor = User(
                email='contractor@test.com',
                first_name='Con',
                last_name='Tractor',
                role='contractor',
                phone_number='0400000005',
                location='Perth, WA',
                abn_number='55443322110',  # Required for Australian users
                is_active=True,
                privacy_consent=True,
                terms_accepted=True,
                terms_accepted_date=datetime.utcnow()
            )
            contractor.set_password('password')
            db.session.add(contractor)
            db.session.flush()
            
            # Create a job and contract first
            job = Job(
                title='Rating Test Job',
                description='Job for rating testing',
                contractor_id=contractor.id,
                category_id=sample_category.id,
                location='Perth, WA',
                budget_min=1000.00,
                budget_max=2000.00,
                status='assigned'
            )
            db.session.add(job)
            db.session.flush()
            
            contract = Contract(
                job_id=job.id,
                contractor_id=contractor.id,
                worker_id=sample_user.id,
                agreed_rate=1500.00,
                rate_type='total',
                start_date=date.today() - timedelta(days=10),
                end_date=date.today(),
                scope_of_work='Test work for rating',
                status='completed'
            )
            db.session.add(contract)
            db.session.flush()
            
            # Create review
            review = Review(
                reviewer_id=contractor.id,
                reviewee_id=sample_user.id,
                job_id=job.id,
                contract_id=contract.id,
                overall_rating=5,
                quality_rating=5,
                communication_rating=4,
                safety_rating=5,
                comment='Excellent work!',
                verified_completion=True
            )
            db.session.add(review)
            db.session.commit()
            
            # Test retrieval
            found_review = Review.query.filter_by(contract_id=contract.id).first()
            assert found_review is not None
            assert found_review.overall_rating == 5
            assert found_review.comment == 'Excellent work!'
            
            # Test weighted score calculation
            weighted_score = found_review.calculate_weighted_score()
            assert weighted_score > 0


class TestNotifications:
    """Test notification system that exists"""
    
    def test_notification_preference_creation(self, app, sample_user):
        """Test notification preferences"""
        with app.app_context():
            pref = NotificationPreference(
                user_id=sample_user.id,
                notification_type=NotificationType.JOB_MATCH,
                email_enabled=True,
                sms_enabled=False,
                push_web_enabled=True,
                quiet_hours_start=time(22, 0),
                quiet_hours_end=time(7, 0)
            )
            db.session.add(pref)
            db.session.commit()
            
            # Test retrieval
            found_pref = NotificationPreference.query.filter_by(user_id=sample_user.id).first()
            assert found_pref is not None
            assert found_pref.email_enabled is True
            assert found_pref.sms_enabled is False
    
    def test_notification_creation(self, app, sample_user):
        """Test notification creation"""
        with app.app_context():
            notification = Notification(
                user_id=sample_user.id,
                notification_type=NotificationType.JOB_MATCH,
                title='New Job Match',
                content='A new job matches your profile',
                priority=5
            )
            db.session.add(notification)
            db.session.commit()
            
            # Test retrieval and methods
            found_notif = Notification.query.filter_by(user_id=sample_user.id).first()
            assert found_notif is not None
            assert found_notif.title == 'New Job Match'
            assert found_notif.is_read is False
            
            # Test marking as read
            found_notif.mark_as_read()
            assert found_notif.is_read is True
