"""
Comprehensive End-to-End Workflow Test for RateRight
Tests the complete contract lifecycle from registration to rating
"""

import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import pytest
import requests
from datetime import datetime, date, timedelta, timezone
from app import create_app
from app.extensions import db
from app.models import User, Job, Application, Contract, Category
from app.models.safety import Review

class TestCompleteWorkflow:
    """Test complete contract workflow end-to-end"""
    
    def __init__(self):
        """Initialize test environment"""
        self.app = create_app()
        self.app.config['TESTING'] = True
        self.app.config['WTF_CSRF_ENABLED'] = False
        self.client = self.app.test_client()
        
        with self.app.app_context():
            # Ensure test users exist
            contractor = User.query.filter_by(email="contractor@test.com").first()
            worker = User.query.filter_by(email="worker@test.com").first()
            
            if not contractor or not worker:
                print("ERROR: Test users not found. Run scripts/create_test_workflow_users.py first")
                raise RuntimeError("Test users must be created first")
            
            # Store IDs instead of objects to avoid session issues
            self.contractor_id = contractor.id
            self.worker_id = worker.id
            
            # Ensure categories exist
            category = Category.query.filter_by(name="General Construction").first()
            if not category:
                category = Category(
                    name="General Construction",
                    description="General construction work",
                    whs_risk_level="medium",
                    is_active=True,
                    sort_order=1
                )
                db.session.add(category)
                db.session.commit()
            
            # Store category ID
            self.category_id = category.id
    
    def test_01_complete_workflow(self):
        """Test the complete workflow from job posting to rating"""
        
        print("\n" + "="*60)
        print("STARTING COMPREHENSIVE END-TO-END WORKFLOW TEST")
        print("="*60)
        
        # Step 1: Login as Contractor
        print("\n1. TESTING CONTRACTOR LOGIN...")
        response = self.client.post('/login', data={
            'email': 'contractor@test.com',
            'password': 'password123'
        }, follow_redirects=True)
        assert response.status_code == 200
        print("✓ Contractor logged in successfully")
        
        # Step 2: Post a Job
        print("\n2. TESTING JOB CREATION...")
        job_data = {
            'title': 'Test Construction Job',
            'description': 'This is a test job for E2E testing',
            'category_id': self.category_id,
            'location': 'Sydney, NSW',
            'budget_min': '5000',
            'budget_max': '10000',
            'whs_requirements': 'Standard WHS requirements apply',
            'white_card_required': 'on',
            'insurance_required': 'on'
        }
        
        response = self.client.post('/jobs/post', data=job_data, follow_redirects=True)
        assert response.status_code == 200
        
        # Get the created job
        with self.app.app_context():
            job = Job.query.filter_by(title='Test Construction Job').first()
            assert job is not None
            job_id = job.id
            print(f"✓ Job created successfully (ID: {job_id})")
        
        # Step 3: Logout and Login as Worker
        print("\n3. TESTING WORKER LOGIN...")
        self.client.get('/logout')
        response = self.client.post('/login', data={
            'email': 'worker@test.com',
            'password': 'password123'
        }, follow_redirects=True)
        assert response.status_code == 200
        print("✓ Worker logged in successfully")
        
        # Step 4: Apply to the Job
        print("\n4. TESTING JOB APPLICATION...")
        application_data = {
            'proposed_rate': '7500',
            'cover_letter': 'I am interested in this job and have the required skills.'
        }
        response = self.client.post(f'/jobs/{job_id}/apply', data=application_data, follow_redirects=True)
        assert response.status_code == 200
        
        with self.app.app_context():
            application = Application.query.filter_by(job_id=job_id).first()
            assert application is not None
            application_id = application.id
            print(f"✓ Application submitted successfully (ID: {application_id})")
        
        # Step 5: Logout and Login as Contractor again
        print("\n5. ACCEPTING APPLICATION AS CONTRACTOR...")
        self.client.get('/logout')
        response = self.client.post('/login', data={
            'email': 'contractor@test.com',
            'password': 'password123'
        }, follow_redirects=True)
        assert response.status_code == 200
        
        # Accept the application
        response = self.client.post(f'/applications/{application_id}/respond', 
                                   data={'action': 'accept'}, 
                                   follow_redirects=True)
        
        with self.app.app_context():
            application = Application.query.get(application_id)
            assert application.status == 'accepted'
            
            # Check contract was created
            contract = Contract.query.filter_by(job_id=job_id).first()
            assert contract is not None
            contract_id = contract.id
            print(f"✓ Application accepted, Contract created (ID: {contract_id})")
        
        # Step 6: Sign Contract as Contractor
        print("\n6. TESTING CONTRACT SIGNING...")
        response = self.client.post(f'/contracts/{contract_id}/sign', follow_redirects=True)
        
        with self.app.app_context():
            contract = Contract.query.get(contract_id)
            assert contract.contractor_signed == True
            print("✓ Contract signed by contractor")
        
        # Step 7: Login as Worker and Sign Contract
        self.client.get('/logout')
        response = self.client.post('/login', data={
            'email': 'worker@test.com',
            'password': 'password123'
        }, follow_redirects=True)
        
        response = self.client.post(f'/contracts/{contract_id}/sign', follow_redirects=True)
        
        with self.app.app_context():
            contract = Contract.query.get(contract_id)
            assert contract.worker_signed == True
            assert contract.status == 'active'
            print("✓ Contract signed by worker - Contract is now ACTIVE")
        
        # Step 8: Mark Work as Complete (Worker)
        print("\n7. TESTING WORK COMPLETION...")
        response = self.client.post(f'/contracts/{contract_id}/mark-complete', follow_redirects=True)
        
        with self.app.app_context():
            contract = Contract.query.get(contract_id)
            assert contract.status == 'pending_review'
            print("✓ Work marked as complete by worker")
        
        # Step 9: Approve Completion (Contractor)
        print("\n8. TESTING COMPLETION APPROVAL...")
        self.client.get('/logout')
        response = self.client.post('/login', data={
            'email': 'contractor@test.com',
            'password': 'password123'
        }, follow_redirects=True)
        
        response = self.client.post(f'/contracts/{contract_id}/approve-completion', follow_redirects=True)
        
        with self.app.app_context():
            contract = Contract.query.get(contract_id)
            # After approval, contract should be in 'completed' or 'pending_rating' state
            assert contract.status in ['completed', 'pending_rating']
            
            # Manually set to pending_rating if needed for testing
            if contract.status == 'completed':
                contract.status = 'pending_rating'
                db.session.commit()
            
            print(f"✓ Work approved by contractor (Status: {contract.status})")
        
        # Step 10: Rate as Contractor
        print("\n9. TESTING RATING SYSTEM...")
        rating_data = {
            'overall_rating': '5',
            'quality_rating': '5',
            'communication_rating': '5',
            'safety_rating': '5',
            'comment': 'Excellent work!',
            'would_work_again': 'on'
        }
        response = self.client.post(f'/contracts/{contract_id}/rate', data=rating_data, follow_redirects=True)
        
        with self.app.app_context():
            contract = Contract.query.get(contract_id)
            assert contract.contractor_rated == True
            review = Review.query.filter_by(contract_id=contract_id, reviewer_id=self.contractor_id).first()
            assert review is not None
            print("✓ Contractor rated the worker")
        
        # Step 11: Rate as Worker
        self.client.get('/logout')
        response = self.client.post('/login', data={
            'email': 'worker@test.com',
            'password': 'password123'
        }, follow_redirects=True)
        
        rating_data = {
            'overall_rating': '5',
            'quality_rating': '5',
            'communication_rating': '5',
            'safety_rating': '5',
            'comment': 'Great client to work with!',
            'would_work_again': 'on'
        }
        response = self.client.post(f'/contracts/{contract_id}/rate', data=rating_data, follow_redirects=True)
        
        with self.app.app_context():
            contract = Contract.query.get(contract_id)
            assert contract.worker_rated == True
            assert contract.status == 'completed'
            review = Review.query.filter_by(contract_id=contract_id, reviewer_id=self.worker_id).first()
            assert review is not None
            print("✓ Worker rated the contractor")
            print(f"✓ Contract completed with mutual ratings (Final Status: {contract.status})")
        
        # Final Summary
        print("\n" + "="*60)
        print("WORKFLOW TEST COMPLETED SUCCESSFULLY!")
        print("="*60)
        print("\nSummary of completed steps:")
        print("1. ✓ Contractor logged in")
        print("2. ✓ Job posted")
        print("3. ✓ Worker logged in")
        print("4. ✓ Worker applied to job")
        print("5. ✓ Contractor accepted application")
        print("6. ✓ Contract created and signed by both parties")
        print("7. ✓ Work marked complete by worker")
        print("8. ✓ Work approved by contractor")
        print("9. ✓ Both parties submitted ratings")
        print("10. ✓ Contract fully completed")
        
        # Check for any issues
        with self.app.app_context():
            # Verify final states
            final_contract = Contract.query.get(contract_id)
            final_job = Job.query.get(job_id)
            
            issues = []
            if final_contract.status != 'completed':
                issues.append(f"Contract status is {final_contract.status}, expected 'completed'")
            if final_job.status != 'assigned':
                issues.append(f"Job status is {final_job.status}, expected 'assigned'")
            if not final_contract.contractor_rated or not final_contract.worker_rated:
                issues.append("Mutual ratings not completed")
            
            if issues:
                print("\nISSUES FOUND:")
                for issue in issues:
                    print(f"  - {issue}")
            else:
                print("\n✅ ALL WORKFLOW STEPS PASSED WITHOUT ISSUES!")
                
            return len(issues) == 0

if __name__ == "__main__":
    # Run the test directly
    try:
        test = TestCompleteWorkflow()
        success = test.test_01_complete_workflow()
        
        if success:
            print("\n🎉 END-TO-END WORKFLOW TEST PASSED!")
            sys.exit(0)
        else:
            print("\n❌ WORKFLOW TEST FAILED - SEE ISSUES ABOVE")
            sys.exit(1)
    except Exception as e:
        print(f"\n❌ TEST FAILED WITH ERROR: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
