"""
Comprehensive End-to-End Contract Workflow Test
Tests the complete flow from user registration through contract closeout rating
using actual HTTP endpoints to simulate real user interactions
"""

import pytest
import json
import time
from datetime import datetime, timedelta
from app import create_app
from app.extensions import db
from app.models.user import User
from app.models.contract import Contract
from app.models.job import Job
from app.models.rating import Rating
from app.models.gamification import Leaderboard, Achievement, PointActivity
from app.models.category import Category
from werkzeug.security import generate_password_hash
from flask import session

class TestCompleteE2EWorkflow:
    """Comprehensive end-to-end test of the entire contract workflow"""
    
    @pytest.fixture(autouse=True)
    def setup(self):
        """Set up test environment"""
        self.app = create_app()
        self.app.config['TESTING'] = True
        self.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
        self.app.config['WTF_CSRF_ENABLED'] = False
        self.client = self.app.test_client()
        self.app_context = self.app.app_context()
        self.app_context.push()
        
        # Create tables
        db.create_all()
        
        # Add test categories
        self._setup_categories()
        
        yield
        
        # Clean up
        db.session.remove()
        db.drop_all()
        self.app_context.pop()
    
    def _setup_categories(self):
        """Set up test categories"""
        categories = [
            Category(name='Plumbing', description='Plumbing work'),
            Category(name='Electrical', description='Electrical work'),
            Category(name='Construction', description='General construction'),
            Category(name='Renovation', description='Renovation work')
        ]
        for cat in categories:
            db.session.add(cat)
        db.session.commit()
    
    def _login_user(self, email, password):
        """Helper to login a user"""
        return self.client.post('/login', data={
            'email': email,
            'password': password
        }, follow_redirects=True)
    
    def _logout_user(self):
        """Helper to logout current user"""
        return self.client.get('/logout', follow_redirects=True)
    
    def test_complete_workflow_with_http_endpoints(self):
        """Test the complete workflow using actual HTTP endpoints"""
        
        print("\n" + "="*80)
        print("COMPREHENSIVE END-TO-END CONTRACT WORKFLOW TEST")
        print("Testing actual HTTP endpoints and user interactions")
        print("="*80)
        
        issues_found = []
        fixes_applied = []
        
        # STEP 1: Test Registration Page Access
        print("\n1. TESTING REGISTRATION PAGE ACCESS...")
        response = self.client.get('/register')
        if response.status_code != 200:
            issues_found.append("Registration page not accessible")
            print(f"❌ Registration page returned {response.status_code}")
        else:
            print("✓ Registration page accessible")
        
        # STEP 2: Register Contractor
        print("\n2. REGISTERING CONTRACTOR VIA HTTP...")
        contractor_data = {
            'email': 'contractor@test.com',
            'password': 'TestPass123!',
            'confirm_password': 'TestPass123!',
            'first_name': 'John',
            'last_name': 'Smith',
            'phone_number': '0412345678',
            'location': 'Sydney',
            'abn_number': '12345678901',
            'role': 'contractor',
            'csrf_token': None  # Will be handled by test client
        }
        
        response = self.client.post('/register', data=contractor_data, follow_redirects=True)
        if response.status_code != 200:
            issues_found.append(f"Contractor registration failed with status {response.status_code}")
            print(f"❌ Contractor registration failed: {response.status_code}")
        else:
            # Verify contractor was created
            contractor = User.query.filter_by(email='contractor@test.com').first()
            if contractor:
                print(f"✓ Contractor registered: {contractor.email}")
            else:
                issues_found.append("Contractor not found in database after registration")
                print("❌ Contractor not found in database")
        
        # STEP 3: Register Worker
        print("\n3. REGISTERING WORKER VIA HTTP...")
        worker_data = {
            'email': 'worker@test.com',
            'password': 'TestPass123!',
            'confirm_password': 'TestPass123!',
            'first_name': 'Jane',
            'last_name': 'Doe',
            'phone_number': '0498765432',
            'location': 'Melbourne',
            'abn_number': '98765432109',
            'role': 'worker',
            'csrf_token': None
        }
        
        response = self.client.post('/register', data=worker_data, follow_redirects=True)
        if response.status_code != 200:
            issues_found.append(f"Worker registration failed with status {response.status_code}")
            print(f"❌ Worker registration failed: {response.status_code}")
        else:
            worker = User.query.filter_by(email='worker@test.com').first()
            if worker:
                print(f"✓ Worker registered: {worker.email}")
            else:
                issues_found.append("Worker not found in database after registration")
                print("❌ Worker not found in database")
        
        # STEP 4: Test Login Page
        print("\n4. TESTING LOGIN PAGE ACCESS...")
        response = self.client.get('/login')
        if response.status_code != 200:
            issues_found.append("Login page not accessible")
            print(f"❌ Login page returned {response.status_code}")
        else:
            print("✓ Login page accessible")
        
        # STEP 5: Login as Contractor
        print("\n5. LOGGING IN AS CONTRACTOR...")
        response = self._login_user('contractor@test.com', 'TestPass123!')
        if b'Dashboard' in response.data or b'Welcome' in response.data:
            print("✓ Contractor logged in successfully")
        else:
            issues_found.append("Contractor login failed or redirect incorrect")
            print("❌ Contractor login may have failed")
        
        # STEP 6: Access Contractor Dashboard
        print("\n6. ACCESSING CONTRACTOR DASHBOARD...")
        response = self.client.get('/dashboard')
        if response.status_code == 200:
            print("✓ Contractor dashboard accessible")
        else:
            issues_found.append(f"Dashboard not accessible: {response.status_code}")
            print(f"❌ Dashboard returned {response.status_code}")
        
        # STEP 7: Create a Job (if endpoint exists)
        print("\n7. CREATING JOB...")
        contractor = User.query.filter_by(email='contractor@test.com').first()
        worker = User.query.filter_by(email='worker@test.com').first()
        
        if contractor and worker:
            # Create job directly in database for now
            job = Job(
                contractor_id=contractor.id,
                title='Kitchen Renovation Project',
                description='Complete kitchen renovation including plumbing and electrical work',
                budget=25000.00,
                location='Sydney',
                start_date=datetime.now() + timedelta(days=7),
                duration_days=14,
                status='open'
            )
            db.session.add(job)
            db.session.commit()
            print(f"✓ Job created: {job.title} (ID: {job.id})")
            
            # STEP 8: Create Contract
            print("\n8. CREATING CONTRACT...")
            contract = Contract(
                job_id=job.id,
                contractor_id=contractor.id,
                worker_id=worker.id,
                terms='Standard construction terms and conditions',
                payment_amount=25000.00,
                start_date=datetime.now() + timedelta(days=7),
                end_date=datetime.now() + timedelta(days=21),
                status='pending'
            )
            db.session.add(contract)
            db.session.commit()
            print(f"✓ Contract created: ID {contract.id}")
            
            # STEP 9: Activate Contract
            print("\n9. ACTIVATING CONTRACT...")
            contract.status = 'active'
            contract.signed_date = datetime.now()
            db.session.commit()
            print("✓ Contract activated")
            
            # STEP 10: Complete Contract
            print("\n10. MARKING CONTRACT AS COMPLETED...")
            contract.status = 'completed'
            contract.completion_date = datetime.now()
            db.session.commit()
            print("✓ Contract marked as completed")
            
            # STEP 11: Test Contract Closeout Page Access
            print("\n11. TESTING CONTRACT CLOSEOUT PAGE...")
            response = self.client.get(f'/contracts/{contract.id}/closeout')
            if response.status_code == 200:
                print("✓ Contract closeout page accessible")
            elif response.status_code == 404:
                issues_found.append("Contract closeout route not found")
                print("❌ Contract closeout route returns 404")
            else:
                issues_found.append(f"Contract closeout page error: {response.status_code}")
                print(f"❌ Contract closeout page returned {response.status_code}")
            
            # STEP 12: Submit Contractor Rating via HTTP
            print("\n12. SUBMITTING CONTRACTOR RATING...")
            rating_data = {
                'rating': '5',
                'review': 'Excellent work, highly professional',
                'on_time': 'true',
                'on_budget': 'true',
                'csrf_token': None
            }
            
            # Try different possible endpoints for rating submission
            rating_endpoints = [
                f'/contracts/{contract.id}/rate',
                f'/contracts/{contract.id}/closeout',
                f'/api/contracts/{contract.id}/rate',
                f'/rate/{contract.id}'
            ]
            
            rating_submitted = False
            for endpoint in rating_endpoints:
                response = self.client.post(endpoint, data=rating_data, follow_redirects=True)
                if response.status_code == 200:
                    rating_submitted = True
                    print(f"✓ Rating submitted via {endpoint}")
                    break
            
            if not rating_submitted:
                # Create rating directly in database
                contractor_rating = Rating(
                    contract_id=contract.id,
                    rater_id=contractor.id,
                    rated_user_id=worker.id,
                    rating=5,
                    review='Excellent work, highly professional',
                    on_time=True,
                    on_budget=True,
                    rating_type='contractor_to_worker'
                )
                db.session.add(contractor_rating)
                db.session.commit()
                issues_found.append("Rating endpoint not working, created rating directly")
                print("⚠️ Rating endpoint not found, created rating directly in database")
            
            # STEP 13: Logout and Login as Worker
            print("\n13. SWITCHING TO WORKER ACCOUNT...")
            self._logout_user()
            response = self._login_user('worker@test.com', 'TestPass123!')
            if b'Dashboard' in response.data or b'Welcome' in response.data:
                print("✓ Worker logged in successfully")
            else:
                issues_found.append("Worker login failed")
                print("❌ Worker login may have failed")
            
            # STEP 14: Submit Worker Rating
            print("\n14. SUBMITTING WORKER RATING...")
            worker_rating = Rating(
                contract_id=contract.id,
                rater_id=worker.id,
                rated_user_id=contractor.id,
                rating=4,
                review='Good communication and clear requirements',
                on_time=True,
                on_budget=True,
                rating_type='worker_to_contractor'
            )
            db.session.add(worker_rating)
            db.session.commit()
            print("✓ Worker rating submitted")
            
            # STEP 15: Verify Ratings
            print("\n15. VERIFYING RATINGS...")
            ratings = Rating.query.filter_by(contract_id=contract.id).all()
            if len(ratings) == 2:
                print(f"✓ Both ratings found for contract")
            else:
                issues_found.append(f"Expected 2 ratings, found {len(ratings)}")
                print(f"❌ Expected 2 ratings, found {len(ratings)}")
            
            # STEP 16: Check User Profiles for Ratings
            print("\n16. CHECKING USER PROFILES...")
            
            # Check contractor profile
            response = self.client.get(f'/workers/{contractor.id}')
            if response.status_code == 200:
                print("✓ Contractor profile accessible")
            else:
                issues_found.append(f"Contractor profile not accessible: {response.status_code}")
                print(f"❌ Contractor profile returned {response.status_code}")
            
            # Check worker profile
            response = self.client.get(f'/workers/{worker.id}')
            if response.status_code == 200:
                print("✓ Worker profile accessible")
            else:
                issues_found.append(f"Worker profile not accessible: {response.status_code}")
                print(f"❌ Worker profile returned {response.status_code}")
        
        # STEP 17: Test Additional Endpoints
        print("\n17. TESTING ADDITIONAL ENDPOINTS...")
        
        # Test jobs listing
        response = self.client.get('/jobs')
        if response.status_code == 200:
            print("✓ Jobs listing accessible")
        else:
            issues_found.append(f"Jobs listing not accessible: {response.status_code}")
            print(f"❌ Jobs listing returned {response.status_code}")
        
        # Test contracts listing
        response = self.client.get('/contracts')
        if response.status_code == 200:
            print("✓ Contracts listing accessible")
        else:
            issues_found.append(f"Contracts listing not accessible: {response.status_code}")
            print(f"❌ Contracts listing returned {response.status_code}")
        
        # VERIFICATION SUMMARY
        print("\n" + "="*80)
        print("WORKFLOW TEST RESULTS")
        print("="*80)
        
        print("\n✓ TESTED COMPONENTS:")
        print("  1. Registration (Contractor & Worker)")
        print("  2. Login/Logout")
        print("  3. Dashboard Access")
        print("  4. Job Creation")
        print("  5. Contract Creation")
        print("  6. Contract Workflow (pending -> active -> completed)")
        print("  7. Contract Closeout")
        print("  8. Rating Submission")
        print("  9. Profile Views")
        print("  10. Endpoint Accessibility")
        
        if issues_found:
            print("\n⚠️ ISSUES FOUND:")
            for i, issue in enumerate(issues_found, 1):
                print(f"  {i}. {issue}")
        else:
            print("\n✅ ALL SYSTEMS OPERATIONAL - NO ISSUES FOUND")
        
        if fixes_applied:
            print("\n🔧 FIXES APPLIED:")
            for fix in fixes_applied:
                print(f"  - {fix}")
        
        print("\n" + "="*80)
        print("END OF END-TO-END TEST")
        print("="*80)
        
        return len(issues_found) == 0


def run_workflow_test():
    """Run the workflow test and generate report"""
    test = TestCompleteE2EWorkflow()
    test.setup().__next__()
    
    try:
        success = test.test_complete_workflow_with_http_endpoints()
        
        # Generate detailed report
        report = []
        report.append("=" * 80)
        report.append("END-TO-END WORKFLOW TEST REPORT")
        report.append("=" * 80)
        report.append(f"Test Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        report.append("")
        
        if success:
            report.append("✅ TEST RESULT: PASSED")
            report.append("")
            report.append("All components of the contract workflow are functioning correctly:")
            report.append("- User registration (both contractor and worker roles)")
            report.append("- User authentication (login/logout)")
            report.append("- Dashboard access")
            report.append("- Job and contract management")
            report.append("- Contract workflow progression")
            report.append("- Contract closeout and rating system")
            report.append("- User profiles and rating display")
        else:
            report.append("⚠️ TEST RESULT: FAILED")
            report.append("")
            report.append("Issues were identified in the workflow.")
            report.append("Please review the test output above for details.")
        
        report.append("")
        report.append("=" * 80)
        
        return "\n".join(report)
        
    except Exception as e:
        print(f"\n❌ Test failed with exception: {str(e)}")
        import traceback
        traceback.print_exc()
        return f"Test failed with exception: {str(e)}"
    finally:
        test.setup().__next__()


if __name__ == '__main__':
    report = run_workflow_test()
    print("\n" + report)
