﻿from flask import render_template, redirect, request, session, jsonify, flash, url_for, current_app
from flask_login import login_required, current_user, logout_user, login_user
from datetime import datetime, date, timedelta
import logging
from app.models import Category
from app.models.user import User
from app.models.time_tracking import TimeEntry
from app.services.notification_service import notification_service
from app.models.notification import NotificationType
from app.extensions import db, limiter, csrf
from flask import Blueprint
from sqlalchemy import or_, and_, cast
from sqlalchemy.dialects.postgresql import JSONB

main = Blueprint('main', __name__, url_prefix='/api')

@main.route('/stats/<period>')
@login_required
def get_stats(period):
    from app.models.contract import Contract
    from datetime import datetime, timedelta, timezone
    from flask import request, jsonify

    # Get user timezone offset (in minutes) from frontend
    offset_minutes = request.args.get('offset', type=int, default=0)
    user_tz = timezone(timedelta(minutes=-offset_minutes))  # JS gives opposite sign

    # Use user-local time
    now_utc = datetime.now(timezone.utc)
    now_local = now_utc.astimezone(user_tz)

    # Calculate week start & end (Monday 00:00 local)
    week_start = now_local - timedelta(days=now_local.weekday())
    week_start = week_start.replace(hour=0, minute=0, second=0, microsecond=0)
    week_end = week_start + timedelta(days=7)

    current_year = now_local.year
    current_month = now_local.month

    active_jobs = 0
    completed_jobs = 0
    pending_amount = 0.0
    total_earnings = 0.0

    contracts = Contract.query.filter_by(worker_id=current_user.id).all()

    for c in contracts:
        # Get actual payment amount if it exists, otherwise use agreed_rate as fallback
        payment = c.payments.first() if c.payments else None
        
        if payment:
            # Use actual payment amounts
            worker_payout = float(payment.net_to_worker or 0)
        else:
            # Fallback to agreed_rate if no payment exists yet
            worker_payout = float(c.agreed_rate or 0)

        if c.status in ['pending_agreement', 'contractor_signed', 'worker_signed', 'active']:
            active_jobs += 1
        if c.status in ['pending_review', 'pending_rating']:
            pending_amount += worker_payout

        if c.mutual_rating_completed_date:
            completed_date_utc = c.mutual_rating_completed_date
            if completed_date_utc.tzinfo is None:
                completed_date_utc = completed_date_utc.replace(tzinfo=timezone.utc)

            completed_local = completed_date_utc.astimezone(user_tz)

            is_weekly = week_start <= completed_local < week_end
            is_monthly = (
                completed_local.year == current_year and
                completed_local.month == current_month
            )
            is_yearly = completed_local.year == current_year

            if (period == 'weekly' and is_weekly) or \
               (period == 'monthly' and is_monthly) or \
               (period == 'yearly' and is_yearly):
                completed_jobs += 1
                total_earnings += worker_payout

    return jsonify({
        "active_jobs": active_jobs,
        "completed_jobs": completed_jobs,
        "pending_amount": round(pending_amount, 2),
        "total_earnings": round(total_earnings, 2),
        "period": period,
        "timezone_offset": offset_minutes
    })

@main.route('/contractor-stats/<period>')
@login_required
@limiter.exempt
def get_contractor_stats(period):
    from app.models.contract import Contract
    from app.models.job import Job
    from datetime import datetime, timedelta, timezone
    from flask import request, jsonify

    # Get timezone offset (in minutes) from frontend
    offset_minutes = request.args.get('offset', type=int, default=0)
    user_tz = timezone(timedelta(minutes=-offset_minutes))  # JS gives opposite sign

    # Current user-local time
    now_utc = datetime.now(timezone.utc)
    now_local = now_utc.astimezone(user_tz)

    # Week start (Monday 00:00 local)
    week_start = now_local - timedelta(days=now_local.weekday())
    week_start = week_start.replace(hour=0, minute=0, second=0, microsecond=0)
    week_end = week_start + timedelta(days=7)

    # Current month/year
    current_year = now_local.year
    current_month = now_local.month

    # Stats containers
    posted_jobs = 0
    pending_applications = 0
    active_contracts = 0
    pending_payouts = 0.0

    # --- JOBS (for posted_jobs + pending_applications) ---
    jobs = Job.query.filter_by(contractor_id=current_user.id).all()
    for j in jobs:
        if j.date_posted:
            job_date_utc = j.date_posted
            if job_date_utc.tzinfo is None:
                job_date_utc = job_date_utc.replace(tzinfo=timezone.utc)
            job_local = job_date_utc.astimezone(user_tz)

            is_weekly = week_start <= job_local < week_end
            is_monthly = (
                job_local.year == current_year and
                job_local.month == current_month
            )
            is_yearly = job_local.year == current_year

            if (period == 'weekly' and is_weekly) or \
               (period == 'monthly' and is_monthly) or \
               (period == 'yearly' and is_yearly):
                posted_jobs += 1

        # count applications (if Job has relationship)
        if hasattr(j, 'applications') and j.applications:
            pending_applications += len([a for a in j.applications if a.status == 'pending'])

    # --- CONTRACTS (for active_contracts + pending_payouts) ---
    contracts = Contract.query.filter_by(contractor_id=current_user.id).all()
    for c in contracts:
        rate = float(c.agreed_rate or 0)

        # Active contracts: count ALL contracts without completed ratings, regardless of period
        if c.status in ['pending_agreement', 'contractor_signed', 'worker_signed', 'active']:
            active_contracts += 1
        
        # Pending payouts: count contracts awaiting review/rating, regardless of period
        if c.status in ['pending_review', 'pending_rating']:
            pending_payouts += rate

    return jsonify({
        "posted_jobs": posted_jobs,
        "pending_applications": pending_applications,
        "active_contracts": active_contracts,
        "pending_payouts": round(pending_payouts, 2),
        "period": period,
        "timezone_offset": offset_minutes
    })

logger = logging.getLogger(__name__)

from datetime import datetime, date


def datetimeformat(value, format='%d-%m-%Y'):
    if value is None:
        return ''
    
    if isinstance(value, (datetime, date)):
        return value.strftime(format)
    
    if isinstance(value, str):
        try:
            dt = datetime.fromisoformat(value)
            return dt.strftime(format)
        except ValueError:
            return value
    
    return value


def register_main_routes(app):
    """Register main web application routes"""
   

    @app.route("/workers")
    def workers():
        """List workers page"""
        from app.models.user import User
        workers = User.query.filter_by(role="worker").all()
        return render_template("workers/list.html", workers=workers)
    
    @app.route("/api/workers")
    def api_workers():
        """API endpoint to get workers list"""
        from app.models.user import User
        workers = User.query.filter_by(role="worker").all()
        workers_data = [
            {
                "id": w.id,
                "email": w.email,
                "first_name": w.first_name,
                "last_name": w.last_name,
                "created_at": w.created_at.isoformat() if w.created_at else None
            }
            for w in workers
        ]
        return jsonify(workers_data)

    @app.route("/find-workers")
    @login_required
    def find_workers():
        """Find workers page - contractors only"""
        from app.models.user import User
        from app.models.category import Category
        from app.utils.auth_decorators import contractor_required
        from sqlalchemy import or_, and_
        
        # Check if user is a contractor
        if current_user.role not in ['contractor', 'employer']:
            flash('This page is only accessible to contractors.', 'error')
            return redirect(url_for('dashboard'))
        
        # Get search query and filters from URL parameters
        search_query = request.args.get('search', '').strip()
        trade_filters = request.args.getlist('trade')  # Get list of selected trades
        gst_filter = request.args.get('gst_registered') == 'true'
        insured_filter = request.args.get('insured') == 'true'
        white_card_filter = request.args.get('white_card') == 'true'
        
        # Base query for active workers with public profiles
        query = User.query.filter_by(role="worker", is_active=True)
        
        # Only show workers who have their profile set to public
        # Using raw SQL for PostgreSQL JSONB operations
        from sqlalchemy import text
        query = query.filter(
            or_(
                User.preferences.is_(None),  # No preferences set - default is public
                text("preferences->'privacy'->>'profile_public' IS NULL"),  # privacy.profile_public not set
                text("preferences->'privacy'->>'profile_public' != 'false'"),  # not explicitly false
            )
        )
        
        # Apply search filter if provided
        if search_query:
            search_pattern = f"%{search_query}%"
            query = query.filter(
                or_(
                    User.first_name.ilike(search_pattern),
                    User.last_name.ilike(search_pattern)
                )
            )
        
        # Apply trade filters if provided (multiple trades with OR logic)
        if trade_filters:
            # Build OR conditions for each selected trade
            trade_conditions = []
            for trade in trade_filters:
                trade_conditions.append(
                    or_(
                        User.primary_trade.ilike(f"%{trade}%"),
                        User.secondary_trade.ilike(f"%{trade}%")
                    )
                )
            # Combine all trade conditions with OR
            if trade_conditions:
                query = query.filter(or_(*trade_conditions))
        
        # Apply compliance filters
        if gst_filter:
            query = query.filter(User.gst_registered == True)
        
        if insured_filter:
            query = query.filter(User.public_liability_insurance == True)
        
        if white_card_filter:
            query = query.filter(User.white_card_number.isnot(None))
        
        workers = query.all()
        
        # Load categories for the trade filter dropdown
        categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
        
        return render_template("contractors/find_workers.html", workers=workers, categories=categories)

    @app.route("/api/contractor/my-jobs")
    @login_required
    def get_contractor_jobs():
        """API endpoint to get contractor's posted jobs"""
        from app.models import Job
        
        # Check if user is a contractor
        if current_user.role not in ['contractor', 'employer']:
            return jsonify({'error': 'Unauthorized'}), 403
        
        # Get contractor's active jobs
        jobs = Job.query.filter_by(
            contractor_id=current_user.id,
            status='open'
        ).order_by(Job.date_posted.desc()).all()
        
        jobs_data = [
            {
                "id": job.id,
                "title": job.title,
                "location": job.location,
                "category": job.category.name if job.category else None,
                "date_posted": job.date_posted.isoformat() if job.date_posted else None
            }
            for job in jobs
        ]
        
        return jsonify({'jobs': jobs_data})

    @app.route("/api/invite-worker-to-job", methods=['POST'])
    @login_required
    def invite_worker_to_job():
        """API endpoint to invite a worker to apply for a job"""
        from app.models import Job, User
        from app.services.notification_service import notification_service
        from app.models.notification import NotificationType
        
        # Check if user is a contractor
        if current_user.role not in ['contractor', 'employer']:
            return jsonify({'error': 'Unauthorized'}), 403
        
        data = request.get_json()
        worker_id = data.get('worker_id')
        job_id = data.get('job_id')
        
        if not worker_id or not job_id:
            return jsonify({'error': 'Missing required fields'}), 400
        
        # Verify job belongs to contractor
        job = Job.query.filter_by(
            id=job_id,
            contractor_id=current_user.id
        ).first()
        
        if not job:
            return jsonify({'error': 'Job not found or unauthorized'}), 404
        
        # Verify worker exists
        worker = User.query.filter_by(id=worker_id, role='worker').first()
        if not worker:
            return jsonify({'error': 'Worker not found'}), 404
        
        # Send notification to worker
        try:
            notification_service.create_notification(
                user_id=worker.id,
                title=f"Job Invitation: {job.title}",
                message=f"{current_user.first_name} {current_user.last_name} has invited you to apply for '{job.title}' in {job.location}. Click to view the job posting.",
                notification_type=NotificationType.JOB_INVITATION,
                related_id=job.id,
                action_url=f"/jobs/{job.id}"
            )
            
            return jsonify({
                'success': True,
                'message': 'Invitation sent successfully'
            })
        except Exception as e:
            current_app.logger.error(f"Error sending job invitation: {str(e)}")
            return jsonify({'error': 'Failed to send invitation'}), 500

    @app.route("/api/worker-details/<int:worker_id>")
    @login_required
    def get_worker_details(worker_id):
        """API endpoint to get detailed worker information including reviews"""
        try:
            from app.models import User
            from app.models.rating import Rating
            
            # Check if user is a contractor
            if current_user.role not in ['contractor', 'employer']:
                return jsonify({'error': 'Unauthorized'}), 403
            
            # Get worker
            worker = User.query.filter_by(id=worker_id, role='worker').first()
            if not worker:
                return jsonify({'error': 'Worker not found'}), 404
            
            # Check if worker's profile is public
            worker_prefs = worker.preferences or {}
            privacy_prefs = worker_prefs.get('privacy', {})
            if not privacy_prefs.get('profile_public', True):
                return jsonify({'error': 'Worker profile is not public'}), 403
            
            # Respect privacy settings for what information to show
            contact_visible = privacy_prefs.get('contact_info_visible', False)
            rating_visible = privacy_prefs.get('rating_visible', True)
            job_history_visible = privacy_prefs.get('job_history_visible', True)
            
            # Get recent reviews (last 5) - where worker was rated
            reviews = Rating.query.filter_by(
                rated_id=worker_id
            ).order_by(Rating.rating_date.desc()).limit(5).all()
            
            reviews_data = []
            for review in reviews:
                reviewer = User.query.get(review.rater_id)
                # Only include reviews from contractors
                if reviewer and reviewer.role in ['contractor', 'employer']:
                    reviews_data.append({
                        'reviewer_name': f"{reviewer.first_name} {reviewer.last_name}",
                        'rating': float(review.overall_score) if review.overall_score else 0,
                        'comment': review.review_text,
                        'created_at': review.rating_date.isoformat() if review.rating_date else None
                    })
            
            # Get completed jobs if job history is visible
            from app.models.contract import Contract
            from app.models.job import Job
            completed_jobs = []
            if job_history_visible:
                # Get completed contracts for this worker
                contracts = Contract.query.filter_by(
                    worker_id=worker_id,
                    status='completed'
                ).order_by(Contract.updated_at.desc()).limit(10).all()
                
                for contract in contracts:
                    if contract.job:
                        # Handle category - it might be a Category object or a string
                        category_name = contract.job.category
                        if hasattr(category_name, 'name'):
                            category_name = category_name.name
                        
                        completed_jobs.append({
                            'title': contract.job.title,
                            'category': category_name,
                            'location': contract.job.location,
                            'completed_date': contract.worker_completion_date.isoformat() if contract.worker_completion_date else contract.updated_at.isoformat(),
                            'contractor_name': contract.get_contractor_name()
                        })
            
            # Get total count of all reviews (not just recent 5)
            total_review_count = Rating.query.filter_by(rated_id=worker_id).count() if rating_visible else 0
            
            worker_data = {
                'id': worker.id,
                'first_name': worker.first_name,
                'last_name': worker.last_name,
                'email': worker.email if contact_visible else None,
                'phone_number': worker.phone_number if contact_visible else None,
                'location': worker.location,
                'profile_picture': worker.profile_picture,
                'primary_trade': worker.primary_trade,
                'secondary_trade': worker.secondary_trade,
                'abn_number': worker.abn_number,
                'gst_registered': worker.gst_registered,
                'jobs_completed': worker.jobs_completed if job_history_visible else 0,
                'average_rating': float(worker.average_rating) if (rating_visible and worker.average_rating) else 0.0,
                'total_reviews': total_review_count,
                'response_rate': float(worker.response_rate) if worker.response_rate else 0.0,
                'public_liability_insurance': worker.public_liability_insurance,
                'public_liability_amount': float(worker.public_liability_amount) if worker.public_liability_amount else None,
                'white_card_number': worker.white_card_number,
                'white_card_expiry': worker.white_card_expiry.isoformat() if worker.white_card_expiry else None,
                'reviews': reviews_data if rating_visible else [],
                'completed_jobs': completed_jobs if job_history_visible else []
            }
            
            return jsonify({'worker': worker_data})
        except Exception as e:
            current_app.logger.error(f"Error getting worker details: {str(e)}")
            import traceback
            traceback.print_exc()
            return jsonify({'error': 'Internal server error'}), 500

    @app.before_request
    def debug_authentication_state():
        """Debug any automatic authentication that might be happening"""
        from flask_login import current_user
        from flask import request, session

        # Only log for web routes (not API routes)
        if not request.path.startswith('/api/'):
            print(f"[?] Route: {request.path}")
            print(f"[?] current_user.is_authenticated: {current_user.is_authenticated}")
            print(f"[?] session keys: {list(session.keys())}")
            if current_user.is_authenticated:
                print(f"[?]  User automatically authenticated: {current_user.email}")
   
   
    app.register_blueprint(main)

    # ================= BETA ACCESS CONTROL =================
    # Can be disabled by commenting out @app.before_request decorator on check_beta_access
    BETA_ACCESS_CODES = ['EARLYBIRD', 'BETA2025', 'RATERIGHT']

    # @app.before_request
    # def check_beta_access():
    #     """Check if user has beta access before allowing site access"""
    #     print('[!!!] CHECK_BETA_ACCESS CALLED')
    #     from flask import request, session, redirect, url_for
    #     from datetime import datetime, timedelta

    #     print(f'[DEBUG] Checking path: {request.path}')

    #     # Skip check for these routes
    #     PUBLIC_ROUTES = [
    #         '/',  # Landing page
    #         '/beta-access',  # Beta access form
    #         '/api/capture-lead',  # Lead capture must work
    #         '/static',  # Static files
    #         '/health',  # Health check
    #         '/test',  # Test route
    #         '/clear-beta',  # For testing
    #         '/login',  # Allow login page
    #         '/logout',  # Allow logout
    #         '/register',  # Allow registration during beta
    #         '/favicon.ico',
    #         '/legal/terms',
    #         '/legal/privacy'
    #     ]

    #     # Check if route should be public
    #     if request.path == '/' or \
    #        request.path == '/beta-access' or \
    #        request.path == '/clear-beta' or \
    #        request.path == '/login' or \
    #        request.path == '/logout' or \
    #        request.path == '/register' or \
    #        request.path == '/favicon.ico' or \
    #        request.path == '/test' or \
    #        request.path == '/health' or \
    #        request.path in ['/legal/terms', '/legal/privacy'] or \
    #        request.path.startswith('/static') or \
    #        request.path.startswith('/api/'):
    #         print(f'[DEBUG] Path {request.path} is PUBLIC - allowing')
    #         return None

    #     print(f'[DEBUG] Path {request.path} is PROTECTED')

    #     # Check for beta access in session
    #     if 'beta_access' in session:
    #         print('[DEBUG] Beta access found in session')
    #         # Check if beta access has expired (31 days)
    #         beta_timestamp = session.get('beta_access_timestamp')
    #         if beta_timestamp:
    #             access_time = datetime.fromisoformat(beta_timestamp)
    #             if datetime.now() - access_time < timedelta(days=31):
    #                 print('[DEBUG] Beta access still valid')
    #                 return None  # Access still valid
    #             else:
    #                 # Beta access expired
    #                 print('[DEBUG] Beta access EXPIRED')
    #                 session.pop('beta_access', None)
    #                 session.pop('beta_access_timestamp', None)
    #     else:
    #         print('[DEBUG] NO beta access in session')

    #     # No beta access - redirect to beta access page
    #     print('[DEBUG] SHOULD REDIRECT TO BETA ACCESS!')
    #     return redirect(url_for('beta_access'))

    # @app.route('/beta-access', methods=['GET', 'POST'])
    # def beta_access():
    #     """Beta access code entry page"""
    #     from flask import request, session, redirect, url_for, render_template
    #     from datetime import datetime

    #     if request.method == 'POST':
    #         code = request.form.get('access_code', '').strip().upper()

    #         if code in BETA_ACCESS_CODES:
    #             # Grant beta access
    #             session['beta_access'] = True
    #             session['beta_access_timestamp'] = datetime.now().isoformat()
    #             session.permanent = True  # Use permanent session
    #             flash('Beta access granted! Welcome to RateRight.', 'success')
    #             return redirect(url_for('dashboard'))
    #         else:
    #             flash('Invalid access code. Please try again.', 'error')
    #             return redirect(url_for('beta_access'))

    #     return render_template('beta_access_alt.html')

    @app.route('/clear-beta')
    def clear_beta():
        """Clear beta access for testing"""
        session.pop('beta_access', None)
        session.pop('beta_access_timestamp', None)
        return "Beta access cleared. <a href='/'>Return to home</a>"

    # ================= END BETA ACCESS CONTROL =================



    @app.route('/debug-session')
    def debug_session():
        """Show current session contents"""
        from flask import session
        return f"<pre>Session contents: {dict(session)}</pre>"

    @app.route('/')
    def index():
        # Serve the complete marketing page directly
        return render_template('countdown.html')

    @app.route('/test')
    def test():
        """Simple test route"""
        return "<h1>[?] RateRight Test Route Working!</h1><p>If you see this, the Flask server is responding correctly.</p>"

    @app.route('/test/db')
    def test_db():
        """Test database connection and show contents"""
        from app.extensions import db
        from app.models import User, Job, Contract, Application, Category
        from sqlalchemy import text
        import json
        from datetime import datetime

        response = []

        try:
            # Test 1: Basic Connection
            db.session.execute(text('SELECT 1'))
            response.append({
                "test": "Database Connection",
                "status": "✅ SUCCESS",
                "message": "Database is connected and responding"
            })

            # Test 2: Count Records in Main Tables
            table_counts = {
                "Users": User.query.count(),
                "Jobs": Job.query.count(),
                "Contracts": Contract.query.count(),
                "Applications": Application.query.count(),
                "Categories": Category.query.count()
            }
            response.append({
                "test": "Record Counts",
                "status": "ℹ️ INFO",
                "counts": table_counts
            })

            # Test 3: Recent Users
            recent_users = User.query.order_by(User.created_at.desc()).limit(5).all()
            response.append({
                "test": "Recent Users",
                "status": "ℹ️ INFO",
                "data": [{
                    "id": user.id,
                    "email": user.email,
                    "role": user.role,
                    "created_at": user.created_at.isoformat() if user.created_at else None
                } for user in recent_users]
            })

            # Test 4: Recent Jobs
            recent_jobs = Job.query.order_by(Job.created_at.desc()).limit(5).all()
            response.append({
                "test": "Recent Jobs",
                "status": "ℹ️ INFO",
                "data": [{
                    "id": job.id,
                    "title": job.title,
                    "status": job.status,
                    "created_at": job.created_at.isoformat() if job.created_at else None
                } for job in recent_jobs]
            })

            # Convert response to pretty JSON
            html_response = f"""
            <html>
            <head>
                <title>Database Test Results</title>
                <style>
                    body {{ font-family: monospace; padding: 20px; }}
                    pre {{ background: #f4f4f4; padding: 15px; border-radius: 5px; }}
                    .success {{ color: green; }}
                    .error {{ color: red; }}
                    .info {{ color: blue; }}
                </style>
            </head>
            <body>
                <h1>🔍 Database Test Results</h1>
                <pre>{json.dumps(response, indent=2)}</pre>
                <p><em>Generated at: {datetime.now().isoformat()}</em></p>
            </body>
            </html>
            """
            return html_response

        except Exception as e:
            error_response = {
                "test": "Database Connection",
                "status": "❌ ERROR",
                "error": str(e),
                "type": type(e).__name__
            }
            return f"""
            <html>
            <head>
                <title>Database Test Error</title>
                <style>
                    body {{ font-family: monospace; padding: 20px; }}
                    pre {{ background: #ffebee; padding: 15px; border-radius: 5px; }}
                    .error {{ color: red; }}
                </style>
            </head>
            <body>
                <h1>❌ Database Test Error</h1>
                <pre>{json.dumps(error_response, indent=2)}</pre>
            </body>
            </html>
            """

    @app.route('/applications')
    @login_required
    def my_applications():
        """View user's job applications or received applications"""
        from app.models import Application
        from app.extensions import db

        if current_user.role == 'worker':
            # Check onboarding completion for workers
            needs_onboarding, missing_steps = current_user.needs_onboarding()
            if needs_onboarding:
                if 'profile' in missing_steps:
                    flash('Please complete your profile setup first.', 'warning')
                    return redirect(url_for('onboarding_profile'))
                elif 'payment' in missing_steps:
                    flash('Please complete your payment setup first.', 'warning')
                    return redirect(url_for('onboarding_payment'))
            
            # Get applications grouped by status
            pending_applications = Application.query.filter_by(
                worker_id=current_user.id,
                status='pending'
            ).order_by(Application.id.desc()).all()

            accepted_applications = Application.query.filter_by(
                worker_id=current_user.id,
                status='accepted'
            ).order_by(Application.id.desc()).all()

            rejected_applications = Application.query.filter_by(
                worker_id=current_user.id,
                status='rejected'
            ).order_by(Application.id.desc()).all()

            return render_template('applications/list.html',
                               pending_applications=pending_applications,
                               accepted_applications=accepted_applications,
                               rejected_applications=rejected_applications)

        elif current_user.role == 'contractor':
            # Get all applications for contractor's jobs
            from app.models import Job
            query = db.session.query(Application).join(Job).filter(
                Job.contractor_id == current_user.id
            )
            
            # Apply job_id filter if provided
            job_id = request.args.get('job_id')
            if job_id:
                try:
                    job_id = int(job_id)
                    query = query.filter(Job.id == job_id)
                except (TypeError, ValueError):
                    flash('Invalid job ID provided', 'error')
            
            applications = query.order_by(Application.id.desc()).all()
            return render_template('applications/contractor_list.html', applications=applications)

        else:
            flash('Access denied.', 'error')
            return redirect(url_for('dashboard'))

    @app.route('/jobs')
    @login_required
    def browse_jobs():
        """Browse available construction jobs"""
        # Check onboarding completion for workers
        if current_user.role == 'worker':
            needs_onboarding, missing_steps = current_user.needs_onboarding()
            if needs_onboarding:
                if 'profile' in missing_steps:
                    flash('Please complete your profile setup before browsing jobs.', 'warning')
                    return redirect(url_for('onboarding_profile'))
                elif 'payment' in missing_steps:
                    flash('Please complete your payment setup before browsing jobs.', 'warning')
                    return redirect(url_for('onboarding_payment'))
        
        if current_user.role == 'contractor':
            flash('As a contractor, you can post jobs and review applications. Workers browse and apply for jobs.', 'info')
        return render_template('jobs/browse.html')

    @app.route('/search')
    def search():
        """Search for jobs"""
        # Jobs route passes no variables, so we do the same
        return render_template('jobs/browse.html')


    @app.route('/api/capture-lead', methods=['POST'])
    def capture_lead():
        """Handle lead capture - direct to Slack only, no database"""
        from app.forms import LeadCaptureForm
        from app.utils.slack import send_lead_to_gsheets

        # Debug: Print what we received
        print(f"[DEBUG] Form data received: {request.form}")

        # Create form WITHOUT CSRF
        class LeadCaptureFormNoCSRF(LeadCaptureForm):
            class Meta:
                csrf = False

        form = LeadCaptureFormNoCSRF()

        if form.validate_on_submit():
            # Prepare lead data
            lead_data = {
                'email': form.email.data,
                'is_beta_tester': form.is_beta_tester.data,
                'wants_updates': form.wants_updates.data,
                'company_size': form.company_size.data,
                'biggest_challenge': form.biggest_challenge.data,
                'construction_focus': form.construction_focus.data
            }

            # Get request info
            request_info = {
                'ip': request.remote_addr,
                'referrer': request.referrer or 'Direct',
                'user_agent': request.headers.get('User-Agent', 'Unknown')
            }

            # Send directly to Slack (no database)
            success = send_lead_to_gsheets(lead_data, request_info)

            # Return appropriate message
            if lead_data['is_beta_tester']:
                message = "Awesome! You're on the beta list. We'll reach out soon with early access."
            else:
                message = "Great! We'll notify you when RateRight launches."

            return jsonify({
                'success': True,
                'message': message,
                'is_beta': lead_data['is_beta_tester']
            })

        # Form validation failed - show what went wrong
        print(f"[DEBUG] Form errors: {form.errors}")
        return jsonify({
            'success': False,
            'errors': form.errors,
            'message': 'Please check all required fields'
        }), 400

    @app.route('/api/report-bug', methods=['POST'])
    def report_bug():
        """Handle bug reports - direct to Slack only, no database"""
        from app.utils.slack import send_bug_report_to_slack
        import re
        import os

        print(f"\n🐛 [BUG REPORT API] New bug report received")
        print(f"🐛 [BUG REPORT API] Request method: {request.method}")
        print(f"🐛 [BUG REPORT API] Content-Type: {request.content_type}")
        print(f"🐛 [BUG REPORT API] Form keys: {list(request.form.keys())}")

        # Check if Slack webhook is configured
        webhook_url = os.environ.get('SLACK_WEBHOOK_URL')
        print(f"🐛 [BUG REPORT API] Slack webhook configured: {bool(webhook_url)}")
        if webhook_url:
            print(f"🐛 [BUG REPORT API] Webhook URL: {webhook_url[:50]}...")

        # Get form data - no CSRF validation for simple bug reports
        description = request.form.get('description', '').strip()
        severity = request.form.get('severity', '').strip()
        page_feature = request.form.get('page_feature', '').strip()
        email = request.form.get('email', '').strip()

        # Auto-collected data
        page_url = request.form.get('page_url', '').strip()
        browser_info = request.form.get('browser_info', '').strip()
        screen_size = request.form.get('screen_size', '').strip()
        device_type = request.form.get('device_type', '').strip()
        console_errors = request.form.get('console_errors', '').strip()
        user_id = request.form.get('user_id', '').strip()

        print(f"🐛 [BUG REPORT API] Description length: {len(description)}")
        print(f"🐛 [BUG REPORT API] Severity: {severity}")
        print(f"🐛 [BUG REPORT API] Page Feature: {page_feature}")
        print(f"🐛 [BUG REPORT API] Device: {device_type}")
        print(f"🐛 [BUG REPORT API] User ID: {user_id}")

        # Basic validation
        if not description:
            print(f"🐛 [BUG REPORT API] ERROR: No description provided")
            return jsonify({
                'success': False,
                'message': 'Please tell us what\'s broken'
            }), 400

        if len(description) < 5:
            print(f"🐛 [BUG REPORT API] ERROR: Description too short ({len(description)} chars)")
            return jsonify({
                'success': False,
                'message': 'Please provide more details'
            }), 400

        if not severity:
            print(f"🐛 [BUG REPORT API] ERROR: No severity provided")
            return jsonify({
                'success': False,
                'message': 'Please select how bad the issue is'
            }), 400

        # Optional email validation
        if email:
            email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
            if not re.match(email_pattern, email):
                print(f"🐛 [BUG REPORT API] ERROR: Invalid email format: {email}")
                return jsonify({
                    'success': False,
                    'message': 'Please enter a valid email address'
                }), 400

        # Prepare enhanced bug report data
        bug_data = {
            'description': description,
            'severity': severity,
            'page_feature': page_feature or 'Unknown',
            'page_url': page_url or request.referrer or 'Unknown',
            'email': email if email else None,
            'browser_info': browser_info,
            'screen_size': screen_size,
            'device_type': device_type,
            'console_errors': console_errors,
            'user_id': user_id if user_id else 'Anonymous'
        }

        # Get request info for context
        request_info = {
            'ip': request.remote_addr,
            'referrer': request.referrer or 'Direct',
            'user_agent': request.headers.get('User-Agent', 'Unknown')
        }

        print(f"🐛 [BUG REPORT API] Prepared data - sending to Slack...")

        # Send directly to Slack (no database)
        try:
            success = send_bug_report_to_slack(bug_data, request_info)
            print(f"🐛 [BUG REPORT API] Slack send result: {success}")

            if success:
                print(f"🐛 [BUG REPORT API] SUCCESS: Bug report sent to Slack!")
                return jsonify({
                    'success': True,
                    'message': 'Thanks! We\'ll look into this.'
                })
            else:
                print(f"🐛 [BUG REPORT API] FAILED: Slack send failed but returning success to user")
                # Show success to user even if Slack fails (graceful degradation)
                return jsonify({
                    'success': True,
                    'message': 'Thanks! We\'ll look into this.'
                })
        except Exception as e:
            print(f"🐛 [BUG REPORT API] EXCEPTION: {str(e)}")
            import traceback
            print(f"🐛 [BUG REPORT API] Full traceback: {traceback.format_exc()}")

            # Still return success to user but log the issue
            return jsonify({
                'success': True,
                'message': 'Thanks! We\'ll look into this.'
            })

    @app.route('/api/cookie-consent', methods=['POST'])
    @csrf.exempt
    def save_cookie_consent():
        """Track user cookie consent preferences in database"""
        from app.models.cookie_consent import CookieConsent
        
        try:
            data = request.get_json()
            consent_type = data.get('consent_type')  # 'all' or 'necessary'
            browser_fingerprint = data.get('browser_fingerprint')
            
            # Validate consent type
            if consent_type not in ['all', 'necessary']:
                return jsonify({
                    'success': False,
                    'message': 'Invalid consent type'
                }), 400
            
            # Create consent record
            consent = CookieConsent(
                consent_type=consent_type,
                ip_address=request.remote_addr,
                user_agent=request.headers.get('User-Agent'),
                browser_fingerprint=browser_fingerprint,
                session_id=session.get('_id'),  # Flask session ID
                referrer_url=request.referrer,
                page_url=data.get('page_url'),
                user_id=current_user.id if current_user.is_authenticated else None,
                consent_version='1.0',
                country_code=data.get('country_code')  # Can be determined from IP
            )
            
            db.session.add(consent)
            db.session.commit()
            
            return jsonify({
                'success': True,
                'message': 'Cookie preferences saved',
                'consent_id': consent.id
            })
                
        except Exception as e:
            print(f"Error saving cookie consent: {str(e)}")
            db.session.rollback()
            return jsonify({
                'success': False,
                'message': 'Failed to save preferences'
            }), 500

    @app.route('/jobs/post', methods=['GET', 'POST'])
    def post_job():
        """Post a new construction job (requires login)"""
        from flask_login import current_user
        from app.models import Job, Category
        from app.extensions import db
        from decimal import Decimal

        if not current_user.is_authenticated:
            flash('Please login to post a job', 'warning')
            # Save the intended destination for after login
            session['next_url'] = url_for('post_job')
            return redirect(url_for('login'))

        if current_user.role != 'contractor':
            flash('Only contractors can post jobs', 'error')
            return redirect(url_for('dashboard'))

        if request.method == 'POST':
            try:
                # Get form data
                title = request.form.get('title', '').strip()
                description = request.form.get('description', '').strip()
                category_id = request.form.get('category_id', type=int)
                location = request.form.get('location', '').strip()
                budget_min = request.form.get('budget_min')
                budget_max = request.form.get('budget_max')
                hourly_rate = request.form.get('hourly_rate')
                whs_requirements = request.form.get('whs_requirements', '').strip()
                white_card_required = 'white_card_required' in request.form
                insurance_required = 'insurance_required' in request.form

                # Get scheduling and workforce data
                start_date = request.form.get('start_date', '').strip()
                start_time = request.form.get('start_time', '').strip()
                duration = request.form.get('duration', '').strip()
                workers_needed = request.form.get('workers_needed', type=int)

                # Validation
                errors = []

                if not title:
                    errors.append('Job title is required')
                if not description:
                    errors.append('Job description is required')
                if not category_id:
                    errors.append('Job category is required')
                if not location:
                    errors.append('Job location is required')

                # Validate category exists
                if category_id:
                    category = Category.query.get(category_id)
                    if not category or not category.is_active:
                        errors.append('Invalid job category selected')

                # Convert budget/rate to Decimal if provided
                budget_min_decimal = None
                budget_max_decimal = None
                hourly_rate_decimal = None

                try:
                    if budget_min:
                        budget_min_decimal = Decimal(str(budget_min))
                        if budget_min_decimal < 0:
                            errors.append('Minimum budget cannot be negative')
                except (ValueError, TypeError):
                    errors.append('Invalid minimum budget amount')

                try:
                    if budget_max:
                        budget_max_decimal = Decimal(str(budget_max))
                        if budget_max_decimal < 0:
                            errors.append('Maximum budget cannot be negative')
                except (ValueError, TypeError):
                    errors.append('Invalid maximum budget amount')

                try:
                    if hourly_rate:
                        hourly_rate_decimal = Decimal(str(hourly_rate))
                        if hourly_rate_decimal < 0:
                            errors.append('Hourly rate cannot be negative')
                except (ValueError, TypeError):
                    errors.append('Invalid hourly rate amount')

                # Validate budget range
                if budget_min_decimal and budget_max_decimal and budget_min_decimal > budget_max_decimal:
                    errors.append('Minimum budget cannot be greater than maximum budget')

                # Process and validate scheduling fields
                start_datetime = None
                if start_date:
                    try:
                        if start_time:
                            # If both date and time provided
                            start_datetime = datetime.strptime(f"{start_date} {start_time}", "%Y-%m-%d %H:%M")
                        else:
                            # If only date provided, set time to start of day
                            start_datetime = datetime.strptime(f"{start_date} 00:00", "%Y-%m-%d %H:%M")
                    except ValueError:
                        errors.append('Invalid start date/time format')

                # Process duration: accept numeric hours or legacy format
                if duration:
                    # Check if it's a numeric value (new format)
                    try:
                        duration_hours = int(duration)
                        if duration_hours < 8:
                            errors.append('Duration must be at least 8 hours')
                        elif duration_hours > 500:
                            errors.append('Duration cannot exceed 500 hours')
                        else:
                            # Store as string of the number only
                            duration = str(duration_hours)
                    except ValueError:
                        # Not numeric - check if it's legacy format
                        duration_mapping = {
                            'half_day': '4',
                            'full_day': '8',
                            'long_day': '10',
                            '2_days': '16',
                            '3_5_days': '32',
                            '1_week_plus': '40'
                        }
                        
                        # Convert legacy format to hours
                        mapped_duration = duration_mapping.get(duration)
                        if mapped_duration:
                            duration = mapped_duration
                        else:
                            # Keep old string format for backwards compatibility
                            pass

                # Validate workers needed (optional but must be valid if provided)
                if workers_needed is not None:
                    try:
                        workers_needed = int(workers_needed)
                        if workers_needed < 1:
                            errors.append('Number of workers needed must be at least 1')
                    except (ValueError, TypeError):
                        errors.append('Invalid number of workers specified')

                if errors:
                    for error in errors:
                        flash(error, 'error')
                    categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
                    return render_template('jobs/post.html', categories=categories)

                # Create new job
                job = Job(
                    title=title,
                    description=description,
                    contractor_id=current_user.id,
                    category_id=category_id,
                    location=location,
                    budget_min=budget_min_decimal,
                    budget_max=budget_max_decimal,
                    hourly_rate=hourly_rate_decimal,
                    whs_requirements=whs_requirements or f"Category: {category.name}. Risk Level: {category.whs_risk_level}.",
                    white_card_required=white_card_required,
                    insurance_required=insurance_required,
                    status='open',
                    start_datetime=start_datetime,
                    duration=duration if duration else None,
                    workers_needed=workers_needed if workers_needed else 1
                )

                db.session.add(job)
                db.session.commit()

                # NOTIFICATION TRIGGER: Job posting notification
                try:
                    # Get nearby workers for this job category and location
                    from app.models.user import User
                    nearby_workers = User.query.filter(
                        User.role == 'worker',
                        User.is_active == True,
                        User.location.ilike(f'%{location}%')  # Simple location matching
                    ).all()

                    # Send notification to relevant workers
                    for worker in nearby_workers:
                        notification_service.send_notification(
                            user_id=worker.id,
                            notification_type=NotificationType.JOB_MATCH,
                            title="New Job Posted",
                            content=f"New {category.name} job: {title} in {location}",
                            action_url=url_for('job_details', job_id=job.id, _external=False)
                        )

                    print(f"[NOTIFICATION] Job posting notifications sent to {len(nearby_workers)} workers")
                except Exception as notification_error:
                    # Don't fail job posting if notification fails
                    print(f"[NOTIFICATION ERROR] Failed to send job posting notifications: {notification_error}")

                flash('Job posted successfully!', 'success')
                return redirect(url_for('job_details', job_id=job.id))

            except Exception as e:
                db.session.rollback()
                flash(f'Error posting job: {str(e)}', 'error')
                categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
                return render_template('jobs/post.html', categories=categories)

        # GET request - show the form
        categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
        return render_template('jobs/post.html', categories=categories)

    @app.route('/jobs/<int:job_id>')
    def job_details(job_id):
        """View specific job details"""
        from app.models import Job, Application
        job = Job.query.get_or_404(job_id)  # Retrieve job from database, or return 404

        # Check if current user has already applied to this job
        user_applied = False
        if current_user.is_authenticated and current_user.role == 'worker':
            existing_app = Application.query.filter_by(
                job_id=job_id,
                worker_id=current_user.id
            ).first()
            user_applied = existing_app is not None

        return render_template('jobs/details.html', job=job, user_applied=user_applied)

    @app.route('/jobs/<int:job_id>/apply', methods=['POST'])
    @login_required
    def apply_to_job(job_id):
        """Apply to a job"""
        if request.method == 'POST':
            from app.models import Application
            from app.extensions import db
            from app.models import Job  # Import Job model

            if current_user.role != 'worker':
                flash('Only workers can apply to jobs.', 'error')
                return redirect(url_for('job_details', job_id=job_id))

            # Check if worker has completed onboarding before allowing job applications
            needs_onboarding, missing_steps = current_user.needs_onboarding()
            if needs_onboarding:
                if 'profile' in missing_steps:
                    flash('Please complete your profile setup before applying to jobs.', 'warning')
                    return redirect(url_for('onboarding_profile'))
                elif 'payment' in missing_steps:
                    flash('Please complete your payment setup before applying to jobs.', 'warning')
                    return redirect(url_for('onboarding_payment'))

            job = Job.query.get_or_404(job_id)

            if job.status != 'open':
                flash('This job is no longer accepting applications.', 'error')
                return redirect(url_for('job_details', job_id=job_id))

            # Check if already applied
            existing_app = Application.query.filter_by(
                job_id=job_id,
                worker_id=current_user.id
            ).first()

            if existing_app:
                flash('You have already applied to this job.', 'warning')
                return redirect(url_for('job_details', job_id=job_id))

            # Get form data
            proposed_rate = request.form.get('proposed_rate')
            cover_letter = request.form.get('cover_letter', '').strip()

            # Validate proposed rate
            proposed_rate_decimal = None
            if proposed_rate:
                try:
                    proposed_rate_decimal = float(proposed_rate)
                    if proposed_rate_decimal < 0:
                        flash('Proposed rate cannot be negative.', 'error')
                        return redirect(url_for('job_details', job_id=job_id))
                except (ValueError, TypeError):
                    flash('Invalid proposed rate.', 'error')
                    return redirect(url_for('job_details', job_id=job_id))

            # Create application
            application = Application(
                job_id=job_id,
                worker_id=current_user.id,
                proposed_rate=proposed_rate_decimal,
                cover_letter=cover_letter,
                abn_verified=True,  # Auto-verify for now
                insurance_verified=current_user.public_liability_insurance,
                status='pending'
            )

            try:
                db.session.add(application)
                # Update job applications count
                job.applications_count = (job.applications_count or 0) + 1
                db.session.commit()

                # NOTIFICATION TRIGGER: Application notification
                try:
                    # Send notification to job poster (contractor)
                    notification_service.send_notification(
                        user_id=job.contractor_id,
                        notification_type=NotificationType.JOB_APPLICATION_UPDATE,
                        title="New Application",
                        content=f"{current_user.first_name} {current_user.last_name} applied to '{job.title}'",
                        action_url=url_for('job_details', job_id=job.id, _external=False)
                    )

                    print(f"[NOTIFICATION] Application notification sent to contractor {job.contractor_id}")
                except Exception as notification_error:
                    # Don't fail application submission if notification fails
                    print(f"[NOTIFICATION ERROR] Failed to send application notification: {notification_error}")

                flash('Application submitted successfully!', 'success')
                return redirect(url_for('dashboard'))
            except Exception as e:
                db.session.rollback()
                flash(f'Error submitting application: {str(e)}', 'error')
                print(f"Database error: {e}")  # For debugging
                return redirect(url_for('job_details', job_id=job_id))

    @app.route('/login', methods=['GET', 'POST'])
    def login():
            """User login page and web form handler"""
            from app.models import User
            from app.extensions import db

            if current_user.is_authenticated:
                return redirect(url_for('dashboard'))

            if request.method == 'POST':
                try:
                    # Handle web form login (creates Flask-Login session)
                    email = request.form.get('email')
                    password = request.form.get('password')

                    if not email or not password:
                        if not email:
                            flash('Email is required', 'error_email')
                        if not password:
                            flash('Password is required', 'error_password')
                        return render_template('auth/login_alt.html')

                    # Add debugging
                    print(f"Login attempt for email: {email}")

                    # Check database connection
                    try:
                        from sqlalchemy import text
                        db.session.execute(text('SELECT 1'))
                        print("âœ… Database connection OK")
                    except Exception as db_error:
                        print(f"âŒ Database connection error: {db_error}")
                        flash('Database connection error. Please try again later.', 'error')
                        return render_template('auth/login_alt.html')

                    # Query user with error handling
                    try:
                        user = User.query.filter_by(email=email).first()
                        print(f"User found: {user is not None}")
                    except Exception as query_error:
                        print(f"âŒ User query error: {query_error}")
                        flash('Error retrieving user information. Please try again.', 'error')
                        return render_template('auth/login_alt.html')

                    if user and user.check_password(password) and user.is_active:
                        # Check if email is verified
                        if not user.email_verified:
                            flash('Please verify your email before logging in. Check your inbox for the verification link.', 'error')
                            return render_template('auth/login_alt.html')
                        
                        # Create Flask-Login session first
                        login_user(user, remember=request.form.get('remember'))
                        
                        # Store previous last_login before updating (for welcome message)
                        previous_login = user.last_login
                        
                        # Update last login timestamp after login
                        user.last_login = datetime.utcnow()
                        db.session.commit()
                        
                        # Store in session for welcome message
                        session['is_first_login'] = previous_login is None
                        
                        flash('Login successful!', 'success')

                        # Check for saved redirect URL (job posting fix)
                        next_url = session.pop('next_url', None)
                        if next_url:
                            return redirect(next_url)

                        # Check if worker needs onboarding
                        if user.role == 'worker':
                            needs_onboarding, missing_steps = user.needs_onboarding()
                            if needs_onboarding:
                                if 'profile' in missing_steps:
                                    flash('Welcome! Please complete your profile to get started.', 'info')
                                    return redirect(url_for('onboarding_profile'))
                        
                        # Optional: Show payment setup reminder if not complete
                        if user.role == 'worker' and not user.is_payment_setup_complete():
                            flash('Reminder: Set up your payment method in Settings to receive payments.', 'warning')

                        return redirect(url_for('dashboard'))
                    else:
                        if not user:
                            flash('No account found with this email', 'error_email')
                        else:
                            flash('Invalid password', 'error_password')

                except Exception as e:
                    print(f"âŒ Login error: {str(e)}")
                    import traceback
                    print(traceback.format_exc())
                    flash('An error occurred during login. Please try again.', 'error')
                    return render_template('auth/login_alt.html')

            return render_template('auth/login_alt.html',)
    @app.route('/register', methods=['GET', 'POST'])
    def register():
            """User registration page and handler"""
            if current_user.is_authenticated:
                return redirect(url_for('dashboard'))

            if request.method == 'POST':
                from app.models.user import User
                from app.extensions import db

                # Get form data
                email = request.form.get('email', '').strip().lower()
                password = request.form.get('password')
                confirm_password = request.form.get('confirm_password')
                first_name = request.form.get('first_name', '').strip()
                last_name = request.form.get('last_name', '').strip()
                role = request.form.get('role')
                phone_number = request.form.get('phone_number', '').strip()
                location = request.form.get('location', '').strip()
                abn_number_raw = request.form.get('abn_number', '').strip()
                # Clean ABN - remove spaces and dashes
                abn_number = abn_number_raw.replace(' ', '').replace('-', '')
                is_gst_registered = request.form.get('is_gst_registered') == 'on'
                marketing_consent = request.form.get('marketing_consent') == 'on'

                # Validation
                errors = []
                has_errors = False
                if not email:
                    errors.append('Email is required')
                elif User.query.filter_by(email=email, is_deleted=False).first():
                    flash('This email is already registered', 'error_email')
                    has_errors = True

                if not password or len(password) < 6:
                    errors.append('Password must be at least 6 characters')
                elif password != confirm_password:
                    errors.append('Passwords do not match')

                if not first_name:
                    errors.append('First name is required')
                if not last_name:
                    errors.append('Last name is required')
                if role not in ['contractor', 'worker']:
                    errors.append('Please select a valid role')
                if not phone_number:
                    errors.append('Phone number is required')
                if not location:
                    errors.append('Location is required')
                if not abn_number or len(abn_number) != 11:
                    errors.append('Valid 11-digit ABN is required')

                if User.query.filter_by(phone_number=phone_number, is_deleted=False).first():
                    flash('This Phone Number is already registered', 'error_phone')
                    has_errors = True
                # Check ABN using cleaned version (exclude soft-deleted users)
                if User.query.filter_by(abn_number=abn_number, is_deleted=False).first():
                    flash('This ABN is already registered', 'error_abn')
                    has_errors = True

                if errors or has_errors:
                    for error in errors:
                        flash(error, 'error')
                    return render_template('auth/register_alt.html')

                try:
                    # Create new user
                    # Generate username from email (before @ symbol)
                    username = email.split('@')[0]

                    # Handle referral code
                    referral_code = None
                    if role == 'contractor':
                        # Generate unique code for contractors
                        import secrets
                        import string
                        chars = string.ascii_uppercase.replace('O', '').replace('I', '') + string.digits.replace('0', '').replace('1', '')
                        
                        for _ in range(10):
                            referral_code = ''.join(secrets.choice(chars) for _ in range(8))
                            # Only check uniqueness among contractors
                            existing = User.query.filter_by(referral_code=referral_code, role='contractor').first()
                            if not existing:
                                break
                    elif role == 'worker':
                        # Get referral code from form if provided
                        worker_referral = request.form.get('referral_code', '').strip()
                        if worker_referral:
                            referral_code = worker_referral.upper()

                    user = User(
                        username=username,  # Auto-generate username from email
                        email=email,
                        first_name=first_name,
                        last_name=last_name,
                        role=role,
                        phone_number=phone_number,
                        location=location,
                        abn_number=abn_number,
                        gst_registered=is_gst_registered,
                        privacy_consent=True,
                        terms_accepted=True,
                        terms_accepted_date=datetime.utcnow(),
                        email_verified=False,  # User needs to verify email
                        referral_code=referral_code
                    )
                    user.set_password(password)

                    db.session.add(user)
                    db.session.flush()  # Get user ID before generating token
                    
                    # Create notification preferences with marketing consent
                    from app.models.notification import NotificationPreference, NotificationType
                    
                    # Create a general preference record for marketing notifications
                    # This will be used for ACHIEVEMENT_UNLOCKED, SYSTEM_ANNOUNCEMENT, etc.
                    marketing_pref = NotificationPreference(
                        user_id=user.id,
                        notification_type=NotificationType.SYSTEM_ANNOUNCEMENT,  # General marketing type
                        consent_given=marketing_consent,
                        consent_date=datetime.utcnow() if marketing_consent else None
                    )
                    db.session.add(marketing_pref)
                    
                    # Generate verification token
                    verification_token = user.generate_verification_token()
                    db.session.commit()
                    
                    # Send verification email
                    from app.services.email_service import email_service
                    verification_url = url_for('verify_email', token=verification_token, _external=True)
                    user_name = f"{user.first_name} {user.last_name}"
                    
                    email_service.send_verification_email(
                        user.email,
                        verification_url,
                        user_name
                    )

                    flash('Registration successful! Please check your inbox to verify your account before logging in.', 'success')
                    return redirect(url_for('login'))

                except Exception as e:
                    db.session.rollback()
                    flash(f'Registration failed: {str(e)}', 'error')
                    return render_template('auth/register_alt.html')

            return render_template('auth/register_alt.html')

    @app.route('/logout')
    def logout():
            """Logout user and completely clear all sessions"""
            from flask import make_response

            logout_user()  # Clear Flask-Login session
            session.clear()  # Clear Flask session

            # Create response that clears everything
            response = make_response('''<!DOCTYPE html>
    <html><head><title>Logging out...</title></head>
    <body><h3>Logging out...</h3>
    <script>
    // Clear all localStorage
    localStorage.clear();
    // Clear all sessionStorage
    sessionStorage.clear();
    // Clear specific tokens
    localStorage.removeItem('access_token');
    localStorage.removeItem('user_data');
    localStorage.removeItem('rateright_token');
    // Force redirect immediately
                        window.location.href = '/login';
    </script></body></html>''')

            # Clear all cookies by setting them to expire
            response.set_cookie('session', '', expires=0)
            response.set_cookie('remember_token', '', expires=0)

            return response

    @app.route('/onboarding/profile', methods=['GET', 'POST'])
    @login_required
    def onboarding_profile():
        """Worker profile setup onboarding step"""
        from app.models.category import Category
        from app.extensions import db
        
        # Only workers need profile onboarding
        if current_user.role != 'worker':
            return redirect(url_for('dashboard'))
        
        # Check if profile is already complete
        if current_user.is_profile_complete():
            # Profile complete, check payment next
            if not current_user.is_payment_setup_complete():
                return redirect(url_for('onboarding_payment'))
            # All done
            return redirect(url_for('dashboard'))
        
        if request.method == 'POST':
            try:
                # Update basic information (some may already be set from registration)
                current_user.first_name = request.form.get('first_name', current_user.first_name)
                current_user.last_name = request.form.get('last_name', current_user.last_name)
                current_user.phone_number = request.form.get('phone_number', current_user.phone_number)
                current_user.location = request.form.get('location', current_user.location)
                current_user.abn_number = request.form.get('abn_number', current_user.abn_number)
                
                # Update primary_trade (required for workers)
                if 'primary_trade' in request.form:
                    selected_trades = request.form.getlist('primary_trade')
                    if selected_trades:
                        current_user.primary_trade = ','.join(selected_trades[:3])
                    else:
                        flash('Please select at least one primary trade', 'error')
                        categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
                        return render_template('onboarding/profile.html', user=current_user, categories=categories)
                
                # Update secondary_trade (optional)
                if 'secondary_trade' in request.form:
                    selected_secondary_trades = request.form.getlist('secondary_trade')
                    if selected_secondary_trades:
                        current_user.secondary_trade = ','.join(selected_secondary_trades)
                
                # Update insurance information (required)
                public_liability = 'public_liability_insurance' in request.form
                if not public_liability:
                    flash('Public liability insurance is required to work on the platform', 'error')
                    categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
                    return render_template('onboarding/profile.html', user=current_user, categories=categories)
                
                current_user.public_liability_insurance = public_liability
                current_user.workers_comp_insurance = 'workers_compensation' in request.form
                
                # Optional: insurance amount and expiry
                if request.form.get('public_liability_amount'):
                    current_user.public_liability_amount = float(request.form.get('public_liability_amount'))
                if request.form.get('insurance_expiry_date'):
                    from datetime import datetime
                    current_user.insurance_expiry_date = datetime.strptime(request.form.get('insurance_expiry_date'), '%Y-%m-%d').date()
                
                db.session.commit()
                
                # Check if profile is now complete
                if current_user.is_profile_complete():
                    flash('Profile setup complete!', 'success')
                    # Move to payment setup
                    return redirect(url_for('onboarding_payment'))
                else:
                    flash('Please complete all required fields', 'error')
                    
            except Exception as e:
                db.session.rollback()
                flash(f'Error saving profile: {str(e)}', 'error')
        
        # Load categories for trade selection
        categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
        return render_template('onboarding/profile.html', user=current_user, categories=categories)

    @app.route('/onboarding/payment', methods=['GET', 'POST'])
    @login_required
    def onboarding_payment():
        """Worker payment setup onboarding step - optional but recommended"""
        from app.extensions import db
        
        # Only workers need payment onboarding
        if current_user.role != 'worker':
            return redirect(url_for('dashboard'))
        
        # Check if profile is complete first
        if not current_user.is_profile_complete():
            flash('Please complete your profile first', 'warning')
            return redirect(url_for('onboarding_profile'))
        
        # Check if payment is already complete
        if current_user.is_payment_setup_complete():
            flash('Your payment setup is already complete!', 'success')
            return redirect(url_for('dashboard'))
        
        # Check Stripe account status
        if current_user.stripe_account_id:
            from app.services.stripe_service import stripe_service
            try:
                account_status = stripe_service.get_account_status(current_user.stripe_account_id)
                
                # Update user's Stripe status
                current_user.stripe_onboarding_complete = account_status['details_submitted']
                current_user.stripe_payouts_enabled = account_status['payouts_enabled']
                current_user.stripe_charges_enabled = account_status['charges_enabled']
                db.session.commit()
                
                # If payment is now complete, redirect to dashboard
                if current_user.is_payment_setup_complete():
                    flash('Payment setup complete! You can now start receiving payments.', 'success')
                    return redirect(url_for('dashboard'))
                    
            except Exception as e:
                app.logger.error(f"Error checking Stripe status: {e}")
        
        # Payment setup is optional - show the page but allow skipping
        return render_template('onboarding/payment.html', user=current_user)

    @app.route('/unsubscribe/<int:user_id>/<token>', methods=['GET'])
    def unsubscribe(user_id, token):
        """Handle email unsubscribe requests"""
        from app.models import User
        from app.models.notification import NotificationPreference, NotificationType
        from app.extensions import db
        
        try:
            # Verify the user exists
            user = User.verify_unsubscribe_token(token, user_id)
            
            if not user:
                flash('Invalid unsubscribe link. Please contact support if you continue to receive unwanted emails.', 'error')
                return render_template('auth/unsubscribe.html', success=False)
            
            # Update all notification preferences to remove marketing consent
            prefs = NotificationPreference.query.filter_by(user_id=user.id).all()
            
            if prefs:
                for pref in prefs:
                    pref.consent_given = False
                    pref.consent_date = None
            else:
                # Create a default preference with consent disabled
                pref = NotificationPreference(
                    user_id=user.id,
                    notification_type=NotificationType.SYSTEM_ANNOUNCEMENT,
                    consent_given=False,
                    email_enabled=True  # Still allow non-marketing emails
                )
                db.session.add(pref)
            
            db.session.commit()
            
            flash('You have been successfully unsubscribed from marketing emails. You will still receive important account and transactional notifications.', 'success')
            return render_template('auth/unsubscribe.html', success=True, user=user)
            
        except Exception as e:
            db.session.rollback()
            logger.error(f"Unsubscribe error: {str(e)}")
            flash('An error occurred while processing your unsubscribe request. Please try again or contact support.', 'error')
            return render_template('auth/unsubscribe.html', success=False)

    @app.route('/forgot-password', methods=['GET', 'POST'])
    def forgot_password():
        """Handle forgot password requests"""
        from app.models import User
        from app.extensions import db
        from app.services.email_service import email_service
        
        # Allow authenticated users if they're coming from settings page
        from_settings = request.form.get('from_settings') == 'true' if request.method == 'POST' else False
        
        if current_user.is_authenticated and not from_settings:
            return redirect(url_for('dashboard'))
        
        if request.method == 'POST':
            email = request.form.get('email', '').strip().lower()
            
            if not email:
                flash('Email is required', 'error')
                return render_template('auth/forgot_password.html')
            
            user = User.query.filter_by(email=email).first()
            
            # Always show success message to prevent email enumeration
            if user:
                try:
                    # Generate reset token
                    token = user.generate_reset_token()
                    db.session.commit()
                    
                    # Send password reset email (bypasses quiet hours - security critical)
                    reset_url = url_for('reset_password', token=token, _external=True)
                    user_name = f"{user.first_name} {user.last_name}" if user.first_name else None
                    
                    # Send email via Resend - sent immediately regardless of notification preferences
                    email_sent = email_service.send_password_reset_email(
                        user.email, 
                        reset_url,
                        user_name
                    )
                    
                    if email_sent:
                        current_app.logger.info(f'Password reset email sent to {email}')
                    else:
                        # Fallback: Log the URL if email service is not configured
                        current_app.logger.warning(f'Email service not configured. Reset URL: {reset_url}')
                    
                except Exception as e:
                    db.session.rollback()
                    current_app.logger.error(f'Error generating reset token: {e}')
            
            # Different message for authenticated users
            if from_settings:
                flash('Password reset link has been sent to your email. Please check your inbox.', 'success')
                return redirect(url_for('dashboard'))
            else:
                flash('If this email is registered, a password reset link has been sent. Please check your inbox.', 'success')
        
        return render_template('auth/forgot_password.html')

    @app.route('/verify-email/<token>')
    def verify_email(token):
        """Handle email verification with token"""
        from app.models import User
        from app.extensions import db
        
        if current_user.is_authenticated:
            flash('Your email is already verified!', 'info')
            return redirect(url_for('dashboard'))
        
        # Find user with this token
        user = User.query.filter_by(email_verification_token=token).first()
        
        if not user:
            flash('Invalid verification link. Please contact support if you continue to have issues.', 'error')
            return redirect(url_for('login'))
        
        if not user.verify_email_token(token):
            flash('This verification link has expired. Please register again or contact support.', 'error')
            return redirect(url_for('login'))
        
        try:
            # Mark email as verified and clear token
            user.email_verified = True
            user.email_verification_token = None
            user.email_verification_expires = None
            db.session.commit()
            
            # Simple success page with auto-redirect
            return render_template('auth/email_verified.html')
        except Exception as e:
            db.session.rollback()
            flash(f'Error verifying email: {str(e)}', 'error')
            return redirect(url_for('login'))

    @app.route('/reset-password/<token>', methods=['GET', 'POST'])
    def reset_password(token):
        """Handle password reset with token"""
        from app.models import User
        from app.extensions import db
        
        if current_user.is_authenticated:
            return redirect(url_for('dashboard'))
        
        # Find user with this token
        user = User.query.filter_by(password_reset_token=token).first()
        
        if not user or not user.verify_reset_token(token):
            flash('Invalid or expired reset link. Please request a new one.', 'error')
            return redirect(url_for('forgot_password'))
        
        if request.method == 'POST':
            password = request.form.get('password')
            confirm_password = request.form.get('confirm_password')
            
            if not password or len(password) < 6:
                flash('Password must be at least 6 characters', 'error')
                return render_template('auth/reset_password.html', token=token)
            
            if password != confirm_password:
                flash('Passwords do not match', 'error')
                return render_template('auth/reset_password.html', token=token)
            
            try:
                # Update password and clear reset token
                user.set_password(password)
                user.clear_reset_token()
                db.session.commit()
                
                flash('Your password has been reset successfully! You can now log in.', 'success')
                return redirect(url_for('login'))
            except Exception as e:
                db.session.rollback()
                current_app.logger.error(f'Error resetting password: {e}')
                flash('An error occurred. Please try again.', 'error')
                return render_template('auth/reset_password.html', token=token)
        
        return render_template('auth/reset_password.html', token=token)

    @app.route('/dashboard')
    @login_required
    def dashboard():
        from app.utils.auth_decorators import onboarding_required
        
        # Check onboarding for workers - only enforce profile completion
        if current_user.role == 'worker':
            needs_onboarding, missing_steps = current_user.needs_onboarding()
            if needs_onboarding:
                if 'profile' in missing_steps:
                    return redirect(url_for('onboarding_profile'))
        
        if current_user.role == 'worker':
            return redirect(url_for('dashboard_worker'))
        elif current_user.role == 'contractor':
            return redirect(url_for('dashboard_contractor'))
        elif current_user.role == 'super_admin':
            return redirect(url_for('dashboard_admin'))
        return "Invalid role", 403

    @app.route('/dashboard/contractor')
    @login_required
    def dashboard_contractor():
            """Contractor dashboard"""
            import traceback

            try:
                from app.models import Job, Application, Contract, Rating
                from app.extensions import db

                if not current_user.is_authenticated or current_user.role != 'contractor':
                    return redirect(url_for('login'))

                # Initialize variables with defaults
                posted_jobs = []
                recent_applications = []
                pending_applications = []
                active_contracts = []
                pending_payouts = 0
                total_applications = 0

                todays_date = date.today()

                # Fetch contractor's posted jobs with error handling
                try:
                    posted_jobs = Job.query.filter_by(contractor_id=current_user.id).order_by(Job.date_posted.desc()).all()
                    print(f"âœ… Fetched {len(posted_jobs)} posted jobs")
                except Exception as e:
                    print(f"âŒ Error fetching posted jobs: {e}")
                    posted_jobs = []

                # Get all applications for contractor's jobs with error handling
                try:
                    recent_applications = db.session.query(Application).join(Job).filter(
                        Job.contractor_id == current_user.id
                    ).order_by(Application.date_applied.desc()).all()
                    print(f"âœ… Fetched {len(recent_applications)} recent applications")
                except Exception as e:
                    print(f"âŒ Error fetching recent applications: {e}")
                    recent_applications = []

                # Get pending applications specifically with error handling
                try:
                    pending_applications = db.session.query(Application).join(Job).filter(
                        Job.contractor_id == current_user.id,
                        Application.status == 'pending'
                    ).all()
                    print(f"âœ… Fetched {len(pending_applications)} pending applications")
                except Exception as e:
                    print(f"âŒ Error fetching pending applications: {e}")
                    pending_applications = []

                # Get contractor's contracts with error handling
                try:
                    active_contracts = Contract.query.filter(
                        Contract.contractor_id == current_user.id,
                        Contract.status.in_(['pending_agreement', 'contractor_signed', 'worker_signed', 'active', 'pending_review', 'pending_rating', 'completed'])
                    ).order_by(Contract.created_at.desc()).all()
                    print(f"âœ… Fetched {len(active_contracts)} active contracts")
                except Exception as e:
                    print(f"âŒ Error fetching active contracts: {e}")
                    active_contracts = []

                # Calculate pending payouts with error handling
                try:
                    pending_payouts = 0
                    for contract in active_contracts:
                        if contract.status in ['active', 'pending_review']:
                            pending_payouts += float(contract.agreed_rate or 0)
                    print(f"âœ… Calculated pending payouts: ${pending_payouts}")
                except Exception as e:
                    print(f"âŒ Error calculating pending payouts: {e}")
                    pending_payouts = 0

                total_applications = len(recent_applications)

                my_reviews = Rating.query.join(Contract).filter(
                    Rating.rated_id == current_user.id,
                    Rating.review_text.isnot(None),
                    Contract.status == 'completed'
                ).order_by(Rating.rating_date.desc()).limit(3).all()

                return render_template('dashboard/contractor.html',
                                     posted_jobs=posted_jobs,
                                     total_applications=total_applications,
                                     recent_applications=recent_applications,
                                     pending_applications=pending_applications,
                                     active_contracts=active_contracts,
                                     pending_payouts=pending_payouts,
                                     todays_date=todays_date,
                                     one_week_span=todays_date + timedelta(days=7),
                                     my_reviews=my_reviews)

            except Exception as e:
                # Capture full error details
                error_details = traceback.format_exc()
                print(f"âŒ DASHBOARD ERROR: {str(e)}")
                print(f"Full traceback:\n{error_details}")

                # Return detailed error page in development, generic in production
                if app.config.get('DEBUG', False):
                    return f"""
                    <h1>Dashboard Error</h1>
                    <h2>Error: {str(e)}</h2>
                    <pre>{error_details}</pre>
                    <h3>Debug Info:</h3>
                    <ul>
                        <li>User authenticated: {current_user.is_authenticated if 'current_user' in locals() else 'Unknown'}</li>
                        <li>User role: {current_user.role if 'current_user' in locals() and hasattr(current_user, 'role') else 'Unknown'}</li>
                        <li>User ID: {current_user.id if 'current_user' in locals() and hasattr(current_user, 'id') else 'Unknown'}</li>
                    </ul>
                    """, 500
                else:
                    return "Internal server error. Please contact support.", 500

    @app.route('/dashboard/worker')
    @login_required
    def dashboard_worker():
        """Worker dashboard"""
        import traceback
        from datetime import date, timedelta
        from flask import render_template, current_app
        from app.models import Application, Contract, Rating

        try:
            if not current_user.is_authenticated or current_user.role != 'worker':
                return redirect(url_for('login'))

            # Check onboarding completion for workers
            needs_onboarding, missing_steps = current_user.needs_onboarding()
            if needs_onboarding:
                if 'profile' in missing_steps:
                    return redirect(url_for('onboarding_profile'))
                elif 'payment' in missing_steps:
                    return redirect(url_for('onboarding_payment'))

            todays_date = date.today()

            applications = Application.query.filter_by(worker_id=current_user.id).order_by(Application.date_applied.desc()).all()
            active_contracts = Contract.query.filter(
                Contract.worker_id == current_user.id,
                Contract.status.in_([
                    'pending_agreement', 'contractor_signed', 'worker_signed',
                    'active', 'pending_review', 'pending_rating', 'completed'
                ])
            ).order_by(Contract.created_at.desc()).all()

            my_reviews = Rating.query.join(Contract).filter(
                Rating.rated_id == current_user.id,
                Rating.review_text.isnot(None),
                Contract.status == 'completed'
            ).order_by(Rating.rating_date.desc()).limit(3).all()

            # Fetch default "weekly" stats directly from same logic
            with current_app.test_request_context():
                from app.main_routes import get_stats
                stats_response = get_stats('weekly')
                stats_data = stats_response.get_json()

            return render_template(
                'dashboard/worker.html',
                todays_date=todays_date,
                one_week_span=todays_date + timedelta(days=7),
                applications=applications,
                active_contracts=active_contracts,
                my_reviews=my_reviews,
                stats_data=stats_data,
                view_period='weekly'
            )

        except Exception as e:
            error_details = traceback.format_exc()
            print(f"❌ WORKER DASHBOARD ERROR: {str(e)}")
            print(error_details)
            if app.config.get('DEBUG', False):
                return f"<pre>{error_details}</pre>", 500
            return "Internal server error", 500


    @app.route('/dashboard/admin')
    @login_required
    def dashboard_admin():
        """Super Admin dashboard with system overview"""
        from datetime import date, timedelta
        from flask import current_app, flash, redirect, url_for
        from app.models import User, Job, Contract, Payment, Dispute
        from app.extensions import db
        from sqlalchemy import func
        import traceback

        try:
            if not current_user.is_authenticated or current_user.role != 'super_admin':
                flash('Access denied. Admin privileges required.', 'error')
                return redirect(url_for('dashboard'))

            todays_date = date.today()
            
            # System-wide statistics
            stats = {
                'total_users': User.query.count(),
                'active_users': User.query.filter_by(is_active=True).count(),
                'total_workers': User.query.filter_by(role='worker').count(),
                'total_contractors': User.query.filter_by(role='contractor').count(),
                'total_jobs': Job.query.count(),
                'open_jobs': Job.query.filter_by(status='open').count(),
                'total_contracts': Contract.query.count(),
                'active_contracts': Contract.query.filter(
                    Contract.status.in_(['active', 'pending_agreement', 'contractor_signed', 'worker_signed'])
                ).count(),
                'total_payments': Payment.query.count(),
                'completed_payments': Payment.query.filter_by(status='completed').count(),
                'pending_disputes': Dispute.query.filter_by(status='open').count(),
                'total_payment_volume': db.session.query(
                    func.sum(Payment.gross_amount)
                ).filter(Payment.status == 'completed').scalar() or 0
            }
            
            # Recent activity
            recent_users = User.query.order_by(User.date_created.desc()).limit(5).all()
            recent_jobs = Job.query.order_by(Job.date_posted.desc()).limit(5).all()
            recent_contracts = Contract.query.order_by(Contract.created_at.desc()).limit(5).all()
            
            return render_template('admin/dashboard.html',
                stats=stats,
                recent_users=recent_users,
                recent_jobs=recent_jobs,
                recent_contracts=recent_contracts
            )

        except Exception as e:
            error_details = traceback.format_exc()
            print(f"❌ ADMIN DASHBOARD ERROR: {str(e)}")
            print(error_details)
            if app.config.get('DEBUG', False):
                return f"<h1>Admin Dashboard Error</h1><pre>{error_details}</pre>", 500
            return "Internal server error", 500


    @app.route('/my-jobs')
    @login_required
    def my_jobs():
            """Display user's jobs"""
            try:
                from app.models.job import Job
                from app.models.contract import Contract

                # Get jobs based on user role
                if current_user.role == 'contractor':
                    # Contractor sees jobs they've posted
                    jobs = Job.query.filter_by(contractor_id=current_user.id).order_by(Job.date_posted.desc()).all()
                    template = 'jobs/employer_jobs.html'
                else:
                    # Worker sees jobs they're working on
                    contracts = Contract.query.filter_by(
                        worker_id=current_user.id
                    ).order_by(Contract.created_at.desc()).all()
                    jobs = [contract.job for contract in contracts if contract.job]
                    template = 'jobs/worker_jobs.html'

                return render_template(template, jobs=jobs)
            except Exception as e:
                app.logger.error(f"Error in my_jobs route: {str(e)}")
                # Fallback to dashboard if there's an error
                flash('Unable to load jobs. Please try again.', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/earnings')
    @login_required
    def earnings():
            """Redirect to worker analytics"""
            # Check if the analytics route exists first
            try:
                return redirect(url_for('analytics_worker'))
            except:
                # If analytics_worker doesn't exist, redirect to payouts
                return redirect(url_for('payouts'))

    @app.route('/profile')
    def profile():
            """User profile page - role-specific templates"""
            if not current_user.is_authenticated:
                flash('Please login to access your profile', 'warning')
                return redirect(url_for('login'))

            # Check onboarding completion for workers
            if current_user.role == 'worker':
                needs_onboarding, missing_steps = current_user.needs_onboarding()
                if needs_onboarding:
                    if 'profile' in missing_steps:
                        return redirect(url_for('onboarding_profile'))
                    elif 'payment' in missing_steps:
                        return redirect(url_for('onboarding_payment'))

            # Import models needed for both roles
            from app.models.contract import Contract

            if current_user.role == 'contractor':
                from app.models.job import Job

                # Contractor-specific metrics
                posted_jobs = Job.query.filter_by(contractor_id=current_user.id).count()
                active_contracts = Contract.query.filter_by(
                    contractor_id=current_user.id,
                    status='active'
                ).count()

                return render_template('auth/contractor_profile.html',
                                      posted_jobs=posted_jobs,
                                      active_contracts=active_contracts)

            # Worker profile (default)
            completed_jobs = Contract.query.filter_by(
                worker_id=current_user.id,
                status='completed'
            ).count()

            return render_template('auth/worker_profile.html',
                                  completed_jobs=completed_jobs)

    @app.route('/health')
    def app_health():
            """Simple health check for the web application"""
            return {
                "status": "healthy",
                "message": "RateRight web application is running",
                "timestamp": datetime.utcnow().isoformat()
            }

        # API info is handled in __init__.py

    @app.route('/applications/<int:application_id>/respond', methods=['GET', 'POST'])
    @login_required
    def respond_to_application(application_id):
            """Accept or reject job application (contractor only)"""
            from app.extensions import db
            from app.models import Application # Import Application model
            from app.models import Job # Import Job model

            if current_user.role != 'contractor':
                flash('Only contractors can respond to applications.', 'error')
                return redirect(url_for('dashboard'))

            application = Application.query.get_or_404(application_id)

            # Check if user owns the job
            if application.job.contractor_id != current_user.id:
                flash('You can only respond to applications for your own jobs.', 'error')
                return redirect(url_for('dashboard'))

            if request.method == 'GET':
                # Show application details for review
                return render_template('applications/respond.html', application=application)

            action = request.form.get('action')

            if action == 'accept':
                # Check if the job can accept more workers
                if not application.job.has_space_for_workers():
                    flash('This job has already reached its worker capacity.', 'error')
                    return redirect(url_for('dashboard_contractor'))
                
                application.status = 'accepted'
                
                # Increment accepted workers count and check if job is now full
                is_job_full = application.job.increment_accepted_workers()
                
                if is_job_full:
                    # If job is full, reject all remaining pending applications
                    other_applications = Application.query.filter_by(
                        job_id=application.job_id,
                        status='pending'
                    ).filter(Application.id != application_id).all()

                    for other_app in other_applications:
                        other_app.status = 'rejected'

                # Create Contract record
                from app.models import Contract
                from datetime import date, timedelta

                # Calculate end date based on job duration
                # Use job's start_datetime if available, otherwise use today
                if application.job.start_datetime:
                    start_date = application.job.start_datetime.date()
                else:
                    start_date = date.today()
                
                # Map duration to days - handles both formats (original codes and human-readable)
                duration_days_map = {
                    # Original format codes
                    'half_day': 0,      # Half day = same day
                    'full_day': 0,      # Full day = same day
                    'long_day': 0,      # Long day = same day
                    '2_days': 1,        # 2 days (start day + 1)
                    '3_5_days': 4,      # 5 days (start day + 4)
                    '1_week_plus': 6,   # 7 days (start day + 6)
                    # Human-readable format (as stored in DB)
                    '4 hours': 0,       # Half day = same day
                    '8 hours': 0,       # Full day = same day
                    '10 hours': 0,      # Long day = same day
                    '2 days': 1,        # 2 days
                    '3-5 days': 4,      # 5 days
                    '1+ weeks': 6       # 7 days
                }
                
                duration = application.job.duration
                days_to_add = duration_days_map.get(duration, 29)  # Default to 30 days if duration not recognized
                
                # Calculate end date
                end_date = start_date + timedelta(days=days_to_add)

                # Debug rate transfer
                proposed_rate = application.proposed_rate
                fallback_rate = application.job.budget_max or application.job.hourly_rate or 0
                final_rate = proposed_rate if proposed_rate is not None else fallback_rate

                print(f"[?] Contract Rate Debug:")
                print(f"   Application proposed_rate: {proposed_rate}")
                print(f"   Job budget_max: {application.job.budget_max}")
                print(f"   Job hourly_rate: {application.job.hourly_rate}")
                print(f"   Final agreed_rate: {final_rate}")

                # Determine if this is hourly or total rate based on job data
                rate_type = 'hourly' if application.job.hourly_rate else 'total'

                # Get user names for snapshot
                contractor = User.query.get(application.job.contractor_id)
                worker = User.query.get(application.worker_id)

                # Create contract with proper workflow status
                contract = Contract(
                    job_id=application.job_id,
                    contractor_id=application.job.contractor_id,
                    worker_id=application.worker_id,
                    contractor_name=f"{contractor.first_name} {contractor.last_name}" if contractor else None,
                    worker_name=f"{worker.first_name} {worker.last_name}" if worker else None,
                    contractor_email=contractor.email if contractor else None,
                    contractor_phone=contractor.phone_number if contractor else None,
                    contractor_abn=contractor.abn_number if contractor else None,
                    contractor_business_name=contractor.business_name if contractor else None,
                    worker_email=worker.email if worker else None,
                    worker_phone=worker.phone_number if worker else None,
                    worker_abn=worker.abn_number if worker else None,
                    worker_business_name=worker.business_name if worker else None,
                    agreed_rate=final_rate,
                    rate_type=rate_type,  # Set correct rate type
                    start_date=start_date,
                    end_date=end_date,
                    scope_of_work=application.job.description or "Contract work as per job posting",
                    status='pending_agreement'  # Correct! Requires both parties to agree
                )

                # Add and commit contract with proper error handling
                db.session.add(contract)
                try:
                    db.session.commit()
                    print(f"[?] Contract created successfully: ID {contract.id}")

                    # Verify what was actually saved to database
                    saved_contract = Contract.query.get(contract.id)
                    print(f"[?] VERIFICATION - Saved contract agreed_rate: {saved_contract.agreed_rate}")
                    print(f"[?] VERIFICATION - Saved contract type: {type(saved_contract.agreed_rate)}")

                    # NOTIFICATION TRIGGER: Contract created - notify worker
                    try:
                        notification_service.send_notification(
                            user_id=application.worker_id,
                            notification_type=NotificationType.CONTRACT_AWARDED,
                            title="Application Accepted!",
                            content=f"Your application for '{application.job.title}' was accepted. Contract #{contract.id} created and ready for review.",
                            action_url=url_for('contracts_review', contract_id=contract.id, _external=False),
                            priority=3,
                            category="job_alerts"
                        )
                        print(f"[NOTIFICATION] Contract creation notification sent to worker {application.worker_id}")
                    except Exception as notification_error:
                        print(f"[NOTIFICATION ERROR] Failed to send contract notification: {notification_error}")

                    # Verify contract was created with valid ID
                    if contract.id:
                        # flash(f'Application accepted! Contract #{contract.id} created and ready for review.', 'success')
                        return redirect(url_for('contracts_review', contract_id=contract.id))
                    else:
                        flash('Contract created but ID assignment failed. Check your dashboard.', 'warning')
                        return redirect(url_for('dashboard_contractor'))

                except Exception as e:
                    db.session.rollback()
                    flash(f'Error creating contract: {str(e)}', 'error')
                    print(f"Contract creation error: {e}")  # For debugging
                    return redirect(url_for('dashboard_contractor'))

            elif action == 'reject':
                application.status = 'rejected'
                
                # NOTIFICATION TRIGGER: Application rejected - notify worker
                try:
                    notification_service.send_notification(
                        user_id=application.worker_id,
                        notification_type=NotificationType.JOB_APPLICATION_UPDATE,
                        title="Application Update",
                        content=f"Your application for '{application.job.title}' was not accepted this time.",
                        action_url=url_for('browse_jobs', _external=False),
                        priority=5
                    )
                    print(f"[NOTIFICATION] Application rejection notification sent to worker {application.worker_id}")
                except Exception as notification_error:
                    print(f"[NOTIFICATION ERROR] Failed to send rejection notification: {notification_error}")
                
                flash(f'Application from {application.worker.first_name} {application.worker.last_name} rejected.', 'info')

            try:
                db.session.commit()
            except Exception as e:
                db.session.rollback()
                flash('Error updating application. Please try again.', 'error')
                return redirect(url_for('applications_contractor'))

            return redirect(url_for('applications_contractor'))

    @app.route('/contracts/<int:contract_id>/review', methods=['GET', 'POST'])
    @login_required
    def contracts_review(contract_id):
        from app.models import Contract
        from app.models.rating import Rating
        from app.models.user import User
        from app.extensions import db
        from app.services.time_tracking_service import time_tracking_service

        contract = Contract.query.get_or_404(contract_id)

        # Check if user is party to this contract
        if current_user.id not in [contract.contractor_id, contract.worker_id]:
            flash('You do not have access to this contract.', 'error')
            return redirect(url_for('dashboard'))

        # ✅ ALWAYS fetch hours_data (for both GET and POST)
        try:
            hours_data = time_tracking_service.get_contract_hours(contract_id)
            if not hours_data or not hours_data.get('success', False):
                hours_data = {
                    'success': False,
                    'summary': {
                        'pending_entries': 0,
                        'approved_entries': 0,
                        'total_hours': 0,
                        'total_regular_hours': 0,
                        'total_overtime_hours': 0
                    },
                    'entries': []
                }
        except Exception as e:
            print(f"Error loading hours data: {e}")
            hours_data = {
                'success': False,
                'summary': {
                    'pending_entries': 0,
                    'approved_entries': 0,
                    'total_hours': 0,
                    'total_regular_hours': 0,
                    'total_overtime_hours': 0
                },
                'entries': []
            }

        # Get ratings for display
        ratings = Rating.query.filter_by(contract_id=contract_id).all()

        reviews = []
        for rating in ratings:
            reviewer = User.query.get(rating.rater_id)
            reviewee = User.query.get(rating.rated_id)
            reviews.append({
                'reviewer': reviewer,
                'reviewee': reviewee,
                'overall_rating': rating.overall_score,
                'quality_rating': rating.quality_score,
                'communication_rating': rating.communication_score,
                'reliability_rating': rating.reliability_score,
                'professionalism_rating': rating.professionalism_score,
                'safety_rating': rating.professionalism_score,
                'comment': rating.review_text,
                'would_work_again': True
            })

        return render_template(
            'contracts/review.html',
            contract=contract,
            reviews=reviews,
            hours_data=hours_data  # ✅ Always pass hours_data
        )


    @app.route('/contracts/<int:contract_id>/sign', methods=['GET', 'POST'])
    @login_required
    def contracts_sign(contract_id):
        """Enhanced signing with signature capture and PDF generation"""
        from app.models import Contract
        from app.extensions import db
        from app.services.pdf_service import ContractPDFService
        import base64
        import os

        contract = Contract.query.get_or_404(contract_id)

        if not contract.can_sign(current_user.id):
            flash('You cannot sign this contract at this time.', 'error')
            return redirect(url_for('contracts_review', contract_id=contract_id))

        # Auto-mark as reviewed when signing
        if current_user.id == contract.contractor_id:
            contract.contractor_reviewed = True
        elif current_user.id == contract.worker_id:
            contract.worker_reviewed = True

        if request.method == 'POST':
            try:
                # Process signature data if provided
                signature_data = request.form.get('signature')

                if signature_data:
                    # Save signature as PNG file (NO DATABASE CHANGES)
                    signatures_dir = 'contracts/signatures'
                    os.makedirs(signatures_dir, exist_ok=True)

                    # Remove base64 prefix if present
                    if 'data:image/png;base64,' in signature_data:
                        signature_data = signature_data.split(',')[1]

                    # Save signature file
                    signature_filename = f"signature_{contract_id}_{current_user.id}.png"
                    signature_path = os.path.join(signatures_dir, signature_filename)

                    with open(signature_path, 'wb') as f:
                        f.write(base64.b64decode(signature_data))

                    # Generate signed PDF using PDF service
                    pdf_service = ContractPDFService()
                    pdf_path = pdf_service.generate_contract_pdf({
                        'contract_id': contract_id,
                        'user_id': current_user.id,
                        'signature_file': signature_path,
                        'contract': contract
                    })

                    current_app.logger.info(f"Generated signed contract PDF: {pdf_path}")

                    # DRIVE INTEGRATION: Upload signed contract to Google Drive
                    if pdf_path and os.path.exists(pdf_path):
                        try:
                            from app.services.drive_oauth_service import DriveOAuthService
                            drive_service = DriveOAuthService()
                            drive_link = drive_service.upload_signed_contract(pdf_path, contract_id)

                            if drive_link:
                                current_app.logger.info(f"Contract {contract_id} successfully uploaded to Google Drive: {drive_link}")
                                flash('Contract PDF uploaded to Google Drive for secure storage.', 'success')
                            else:
                                current_app.logger.warning(f"Drive upload failed for contract {contract_id} - OAuth may need renewal")
                                # Don't fail the signing process, just log the issue

                        except Exception as drive_error:
                            current_app.logger.error(f"Drive upload error for contract {contract_id}: {str(drive_error)}")
                            # Drive upload failure shouldn't break contract signing
                            pass

                # Use existing sign_contract method (preserves all existing logic)
                success = contract.sign_contract(current_user.id)

                if success:
                    db.session.commit()

                    # NOTIFICATION TRIGGER: Contract signed (non-blocking)
                    from threading import Thread
                    def send_contract_notifications():
                        if contract.status == 'active':
                            # Notify both parties that contract is now active
                            try:
                                # Notify worker
                                if current_user.id == contract.contractor_id:
                                    notification_service.send_notification(
                                        user_id=contract.worker_id,
                                        notification_type=NotificationType.CONTRACT_AWARDED,
                                        title="Contract Fully Signed!",
                                        content=f"Contract #{contract.id} for '{contract.job.title}' is now active. Work can begin!",
                                        action_url=url_for('contracts_review', contract_id=contract.id, _external=False),
                                        priority=3
                                    )
                                # Notify contractor
                                else:
                                    notification_service.send_notification(
                                        user_id=contract.contractor_id,
                                        notification_type=NotificationType.CONTRACT_AWARDED,
                                        title="Contract Fully Signed!",
                                        content=f"Contract #{contract.id} for '{contract.job.title}' is now active.",
                                        action_url=url_for('contracts_review', contract_id=contract.id, _external=False),
                                        priority=3
                                    )
                                print(f"[NOTIFICATION] Contract activation notification sent")
                            except Exception as notification_error:
                                print(f"[NOTIFICATION ERROR] Failed to send activation notification: {notification_error}")
                        else:
                            # Notify other party that contract was signed
                            try:
                                other_party_id = contract.worker_id if current_user.id == contract.contractor_id else contract.contractor_id
                                notification_service.send_notification(
                                    user_id=other_party_id,
                                    notification_type=NotificationType.CONTRACT_AWARDED,
                                    title="Contract Awaiting Your Signature",
                                    content=f"Contract #{contract.id} for '{contract.job.title}' has been signed by the other party. Please review and sign.",
                                    action_url=url_for('contracts_review', contract_id=contract.id, _external=False),
                                    priority=3
                                )
                                print(f"[NOTIFICATION] Contract signature notification sent to user {other_party_id}")
                            except Exception as notification_error:
                                print(f"[NOTIFICATION ERROR] Failed to send signature notification: {notification_error}")
                    
                    # Send notifications in background thread
                    Thread(target=send_contract_notifications).start()
                    
                    if contract.status == 'active':
                        flash('Contract fully executed! Work can now begin.', 'success')
                    else:
                        flash('Contract signed successfully. Waiting for other party.', 'success')
                else:
                    flash('Failed to sign contract.', 'error')

            except Exception as e:
                current_app.logger.error(f"Signature processing error: {str(e)}")
                # Return JSON for AJAX requests
                if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                    return jsonify({'success': False, 'error': str(e)}), 500
                flash('Signature processing failed, but contract signing completed.', 'warning')

            # Check if this is an AJAX request and return JSON
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return jsonify({'success': True, 'message': 'Contract signed successfully'})

            return redirect(url_for('contracts_review', contract_id=contract_id))

        # GET request - show signing confirmation page
        return render_template('contracts/review.html', contract=contract, show_sign_form=True)


    @app.route('/contracts/<int:contract_id>/mark-complete', methods=['POST'])
    @login_required
    def mark_contract_complete(contract_id):
            """Worker marks contract work as complete"""
            from app.models import Contract
            from app.extensions import db

            contract = Contract.query.get_or_404(contract_id)

            # Only worker can mark as complete
            if contract.worker_id != current_user.id:
                flash('Only the worker can mark work as complete.', 'error')
                return redirect(url_for('contract_closeout', contract_id=contract_id))

            if contract.status != 'active':
                flash('Contract must be active to mark complete.', 'error')
                return redirect(url_for('contract_closeout', contract_id=contract_id))

            # Update contract status
            contract.status = 'pending_review'

            # Find associated payment if exists
            payment = contract.payments.filter_by(status='held_escrow').first()
            if payment:
                payment.status = 'pending_release'
                payment.release_conditions_met = True

            db.session.commit()
            
            # NOTIFICATION TRIGGER: Worker marked work complete - notify contractor
            try:
                notification_service.send_notification(
                    user_id=contract.contractor_id,
                    notification_type=NotificationType.CONTRACT_COMPLETED,
                    title="Work Marked Complete",
                    content=f"Worker has marked work complete on contract #{contract.id} for '{contract.job.title}'. Please review.",
                    action_url=url_for('contract_closeout', contract_id=contract.id, _external=False),
                    priority=3
                )
                print(f"[NOTIFICATION] Work completion notification sent to contractor {contract.contractor_id}")
            except Exception as notification_error:
                print(f"[NOTIFICATION ERROR] Failed to send completion notification: {notification_error}")
            
            flash('Work marked as complete - awaiting contractor review.', 'success')
            return redirect(url_for('contract_closeout', contract_id=contract_id))

    @app.route('/contracts/<int:contract_id>/approve-completion', methods=['POST'])
    @login_required
    def approve_contract_completion(contract_id):
            """Contractor approves work completion - ENFORCES MANDATORY RATING"""
            from app.models import Contract
            from app.extensions import db
            from app.services.rating_service import rating_service
            from datetime import datetime

            contract = Contract.query.get_or_404(contract_id)

            # Only contractor can approve completion
            if contract.contractor_id != current_user.id:
                flash('Only the contractor can approve completion.', 'error')
                return redirect(url_for('contract_closeout', contract_id=contract_id))

            if contract.status != 'pending_review':
                flash('Contract is not pending completion review.', 'error')
                return redirect(url_for('contract_closeout', contract_id=contract_id))

            # CRITICAL: Check if mandatory ratings are complete before allowing completion
            completion_validation = rating_service.validate_contract_completion_request(
                contract_id, current_user.id
            )

            if not completion_validation['can_complete']:
                # If ratings are required, transition to rating stage instead of completing
                if completion_validation.get('requires_rating'):
                    rating_transition = rating_service.transition_contract_to_rating_stage(contract_id)
                    if rating_transition['success']:
                        # CRITICAL FIX: Redirect directly to rating page with payment hold flash message
                        #flash(f'Work approved! Payment of ${"{:,.2f}".format(contract.agreed_rate)} is held until both parties rate each other.', 'warning')
                        return redirect(url_for('rate_contract', contract_id=contract_id))
                    else:
                        flash(f'Error transitioning to rating stage: {rating_transition["error"]}', 'error')
                else:
                    flash(completion_validation['error'], 'error')
                return redirect(url_for('contract_closeout', contract_id=contract_id))

            # If we reach here, ratings are complete - proceed with completion
            # Find payment in escrow
            payment = contract.payments.filter_by(status='pending_release').first()
            if payment:
                payment.status = 'released'
                payment.date_released = datetime.utcnow()
                
                # Auto-generate invoice for GST-registered workers
                try:
                    invoice = payment.auto_generate_invoice()
                    if invoice:
                        print(f"📄 Auto-generated invoice: {invoice.invoice_number}")
                        flash(f'Invoice {invoice.invoice_number} has been automatically generated.', 'info')
                except Exception as invoice_error:
                    print(f"⚠️ Invoice generation failed: {invoice_error}")

            # Update contract status to completed (ratings already verified)
            contract.mark_as_completed()
            contract.mutual_rating_completed_date = datetime.utcnow()

            db.session.commit()
            flash('Work approved and payment released successfully! Contract completed with mutual ratings.', 'success')
            return redirect(url_for('contract_closeout', contract_id=contract_id))

    @app.route('/contracts/<int:contract_id>/dispute-completion', methods=['POST'])
    @login_required
    def dispute_contract_completion(contract_id):
            """Contractor disputes work completion"""
            from app.models import Contract
            from app.extensions import db

            contract = Contract.query.get_or_404(contract_id)

            # Only contractor can dispute
            if contract.contractor_id != current_user.id:
                flash('Only the contractor can dispute completion.', 'error')
                return redirect(url_for('contract_closeout', contract_id=contract_id))

            if contract.status != 'pending_review':
                flash('Contract is not pending completion review.', 'error')
                return redirect(url_for('contract_closeout', contract_id=contract_id))

            dispute_reason = request.form.get('reason', 'Work does not meet requirements')

            # Update contract status
            contract.status = 'disputed'

            # Find payment and mark as disputed
            payment = contract.payments.filter_by(status='pending_release').first()
            if payment:
                payment.status = 'disputed'

            db.session.commit()
            flash(f'Completion disputed: {dispute_reason}', 'warning')
            return redirect(url_for('contract_closeout', contract_id=contract_id))

    @app.route('/contracts', methods=['GET'])
    @login_required
    def contracts_list():
            """List all contracts for current user"""
            from app.models import Contract

            # Check onboarding completion for workers
            if current_user.role == 'worker':
                needs_onboarding, missing_steps = current_user.needs_onboarding()
                if needs_onboarding:
                    if 'profile' in missing_steps:
                        flash('Please complete your profile setup first.', 'warning')
                        return redirect(url_for('onboarding_profile'))
                    elif 'payment' in missing_steps:
                        flash('Please complete your payment setup first.', 'warning')
                        return redirect(url_for('onboarding_payment'))

            if current_user.role == 'contractor':
                contracts = Contract.query.filter_by(contractor_id=current_user.id).order_by(Contract.created_at.desc()).all()
            else:
                contracts = Contract.query.filter_by(worker_id=current_user.id).order_by(Contract.created_at.desc()).all()

            return render_template('contracts/list.html', contracts=contracts)

    @app.route('/applications/<int:application_id>/accept', methods=['POST'])
    @login_required
    def accept_application(application_id):
            """Accept a job application and create contract"""
            from app.models import Application, Contract
            from datetime import date, timedelta

            if not current_user.is_authenticated or current_user.role != 'contractor':
                flash('Only contractors can accept applications', 'error')
                return redirect(url_for('login'))

            application = Application.query.get_or_404(application_id)

            # Check if contractor owns this job
            if application.job.contractor_id != current_user.id:
                flash('You can only accept applications for your own jobs', 'error')
                return redirect(url_for('applications_contractor_list'))

            if application.status != 'pending':
                flash('Application has already been processed', 'warning')
                return redirect(url_for('applications_contractor_list'))

            try:
                # Accept the application
                application.status = 'accepted'

                # Close the job
                application.job.status = 'assigned'

                # Create contract automatically
                start_date = date.today() + timedelta(days=7)  # Start in 1 week
                end_date = start_date + timedelta(days=30)  # 30 day contract

                # Get user names for snapshot
                worker = User.query.get(application.worker_id)

                contract = Contract(
                    job_id=application.job_id,
                    contractor_id=current_user.id,
                    worker_id=application.worker_id,
                    contractor_name=f"{current_user.first_name} {current_user.last_name}",
                    worker_name=f"{worker.first_name} {worker.last_name}" if worker else None,
                    contractor_email=current_user.email,
                    contractor_phone=current_user.phone_number,
                    contractor_abn=current_user.abn_number,
                    contractor_business_name=current_user.business_name,
                    worker_email=worker.email if worker else None,
                    worker_phone=worker.phone_number if worker else None,
                    worker_abn=worker.abn_number if worker else None,
                    worker_business_name=worker.business_name if worker else None,
                    agreed_rate=application.proposed_rate if application.proposed_rate is not None else (application.job.budget_max or application.job.hourly_rate or 5000.00),
                    rate_type='total',
                    start_date=start_date,
                    end_date=end_date,
                    scope_of_work=application.job.description,
                    payment_terms='completion',
                    status='pending_agreement'
                )

                db.session.add(contract)

                # Reject other pending applications for this job
                other_applications = Application.query.filter_by(
                    job_id=application.job_id,
                    status='pending'
                ).filter(Application.id != application_id).all()

                for other_app in other_applications:
                    other_app.status = 'rejected'

                db.session.commit()

                # NOTIFICATION TRIGGER: Contract acceptance notification
                try:
                    # Send notification to worker that application was accepted
                    notification_service.send_notification(
                        user_id=application.worker_id,
                        notification_type=NotificationType.CONTRACT_AWARDED,
                        title="Application Accepted!",
                        content=f"Your application for '{application.job.title}' was accepted. Contract #{contract.id} created.",
                        action_url=url_for('contracts_review', contract_id=contract.id, _external=False),
                        category="job_alerts"
                    )

                    print(f"[NOTIFICATION] Contract acceptance notification sent to worker {application.worker_id}")
                except Exception as notification_error:
                    # Don't fail contract creation if notification fails
                    print(f"[NOTIFICATION ERROR] Failed to send contract acceptance notification: {notification_error}")

                flash(f'Application accepted! Contract #{contract.id} created and ready for review.', 'success')

            except Exception as e:
                db.session.rollback()
                flash(f'Error accepting application: {str(e)}', 'error')

            return redirect(url_for('applications_contractor_list'))

    @app.route('/api/contracts/<int:contract_id>/time-tracking')
    @login_required
    @limiter.exempt
    def time_tracking_api(contract_id):
        """API endpoint to get time tracking data for a contract"""
        from app.models import Contract
        from app.extensions import db

        contract = Contract.query.get_or_404(contract_id)

        # Check if user has access to this contract
        if current_user.id not in [contract.contractor_id, contract.worker_id]:
            return jsonify({'error': 'Access denied'}), 403

        # Get time entries for this contract
        time_entries = TimeEntry.query.filter_by(
            contract_id=contract_id,
            worker_id=contract.worker_id
        ).order_by(TimeEntry.clock_in.desc()).all()

        # Calculate summary statistics
        total_overtime = sum((entry.overtime_hours or 0)for entry in time_entries)
        total_regular = sum((entry.regular_hours or 0)for entry in time_entries)
        total_hours = sum((entry.regular_hours or 0) + (entry.overtime_hours or 0) for entry in time_entries)
        week_entries = [entry for entry in time_entries if entry.work_date >= (datetime.now().date() - timedelta(days=7))]
        week_hours = sum((entry.regular_hours or 0) + (entry.overtime_hours or 0) for entry in week_entries)

        # Check for active session
        active_entry = TimeEntry.query.filter_by(
            contract_id=contract_id,
            worker_id=contract.worker_id,
            clock_out=None
        ).first()

        return jsonify({
            'total_regular': round(total_regular, 2),
            'total_overtime': round(total_overtime, 2),
            'total_hours': round(total_hours, 2),
            'week_hours': round(week_hours, 2),
            'is_clocked_in': bool(active_entry),
            'clock_in_time': active_entry.clock_in.isoformat() if active_entry else None,
            'active_entry_id': active_entry.id if active_entry else None,
            'recent_entries': [{
                'id': entry.id,
                'date': entry.work_date.strftime('%Y-%m-%d'),
                'start_time': entry.clock_in.strftime('%H:%M'),
                'end_time': entry.clock_out.strftime('%H:%M') if entry.clock_out else None,
                'regular_hours': entry.regular_hours or 0,
                'overtime_hours': entry.overtime_hours or 0,
                'total_hours': (entry.regular_hours or 0) + (entry.overtime_hours or 0),
                'break_minutes': entry.total_break_minutes or 0,
                'description': entry.description or '',
                'status': 'approved' if entry.is_approved else 'pending'
            } for entry in time_entries[:5]]
        })

    @app.route('/api/contracts/<int:contract_id>/clock-in', methods=['POST'])
    @login_required
    def clock_in_api(contract_id):
        """Clock in for a contract"""
        from app.models import Contract
        from app.extensions import db

        contract = Contract.query.get_or_404(contract_id)

        # Only worker can clock in
        if current_user.id != contract.worker_id:
            return jsonify({'error': 'Only the worker can clock in'}), 403

        # Check if already clocked in
        active_entry = TimeEntry.query.filter_by(
            contract_id=contract_id,
            worker_id=current_user.id,
            clock_out=None
        ).first()

        if active_entry:
            return jsonify({'error': 'Already clocked in'}), 400

        # Create new time entry
        entry = TimeEntry(
            contract_id=contract_id,
            worker_id=current_user.id,
            work_date=datetime.now().date(),
            clock_in=datetime.utcnow(),
            description=request.json.get('description', '')
        )

        db.session.add(entry)
        db.session.commit()

        return jsonify({
            'success': True,
            'entry_id': entry.id,
            'clock_in': entry.clock_in.isoformat()
        })

    @app.route('/api/time-entries/<int:entry_id>/clock-out', methods=['POST'])
    @login_required
    def clock_out_api(entry_id):
        """Clock out of current time entry"""
        from app.extensions import db

        entry = TimeEntry.query.get_or_404(entry_id)

        # Verify ownership
        if entry.worker_id != current_user.id:
            return jsonify({'error': 'Unauthorized'}), 403

        if entry.clock_out:
            return jsonify({'error': 'Already clocked out'}), 400

        # Clock out
        entry.clock_out = datetime.utcnow()
        entry.description = request.json.get('description', entry.description)
        entry.calculate_total_time()  # This method is defined in the TimeEntry model

        db.session.commit()

        return jsonify({
            'success': True,
            'clock_out': entry.clock_out.isoformat(),
            'total_hours': (entry.regular_hours or 0) + (entry.overtime_hours or 0)
        })

    @app.route('/api/time-entries/<int:entry_id>/break', methods=['POST'])
    @login_required
    def toggle_break_api(entry_id):
        """Toggle break for a time entry"""
        from app.extensions import db

        entry = TimeEntry.query.get_or_404(entry_id)

        # Verify ownership
        if entry.worker_id != current_user.id:
            return jsonify({'error': 'Unauthorized'}), 403

        if entry.clock_out:
            return jsonify({'error': 'Cannot modify breaks after clock out'}), 400

        # Toggle break
        if entry.break_start and not entry.break_end:
            # End break
            success = entry.end_break()
            status = 'break_ended'
        else:
            # Start break
            success = entry.start_break()
            status = 'break_started'

        if success:
            db.session.commit()
            return jsonify({
                'success': True,
                'status': status,
                'total_break_minutes': entry.total_break_minutes
            })
        else:
            return jsonify({'error': 'Invalid break operation'}), 400

    @app.route('/contracts/<int:contract_id>')
    @login_required
    def contract_review(contract_id):
        """Review contract details and sign"""
        from app.models import Contract
        from app.models.rating import Rating
        from app.models.user import User
        from app.extensions import db
        from app.services.time_tracking_service import time_tracking_service

        contract = Contract.query.get_or_404(contract_id)

        # Check authorization
        if current_user.id not in [contract.contractor_id, contract.worker_id]:
            flash('You are not authorized to view this contract.', 'danger')
            return redirect(url_for('dashboard'))

        # ✅ ADD THIS: Fetch hours_data (same as the other route)
        try:
            hours_data = time_tracking_service.get_contract_hours(contract_id)
            if not hours_data or not hours_data.get('success', False):
                hours_data = {
                    'success': False,
                    'summary': {
                        'pending_entries': 0,
                        'approved_entries': 0,
                        'total_hours': 0,
                        'total_regular_hours': 0,
                        'total_overtime_hours': 0
                    },
                    'entries': []
                }
        except Exception as e:
            print(f"Error loading hours data: {e}")
            hours_data = {
                'success': False,
                'summary': {
                    'pending_entries': 0,
                    'approved_entries': 0,
                    'total_hours': 0,
                    'total_regular_hours': 0,
                    'total_overtime_hours': 0
                },
                'entries': []
            }

        # ✅ ADD THIS: Get ratings
        ratings = Rating.query.filter_by(contract_id=contract_id).all()
        reviews = []
        for rating in ratings:
            reviewer = User.query.get(rating.rater_id)
            reviewee = User.query.get(rating.rated_id)
            reviews.append({
                'reviewer': reviewer,
                'reviewee': reviewee,
                'overall_rating': rating.overall_score,
                'quality_rating': rating.quality_score,
                'communication_rating': rating.communication_score,
                'reliability_rating': rating.reliability_score,
                'professionalism_rating': rating.professionalism_score,
                'safety_rating': rating.professionalism_score,
                'comment': rating.review_text,
                'would_work_again': True
            })

        # Calculate payment amounts for display
        # Try to parse duration as numeric hours first (new format)
        print(f"🔍 DEBUG Payment Calc - Contract {contract_id}:")
        print(f"   Job duration (raw): '{contract.job.duration}' (type: {type(contract.job.duration).__name__})")
        
        try:
            hours = int(contract.job.duration)
            print(f"   ✅ SUCCESS: Parsed as numeric hours: {hours}")
        except (ValueError, TypeError) as e:
            # Legacy format - use mapping
            print(f"   ❌ FAILED to parse as int: {e}")
            duration_hours = {
                'half_day': 4,
                'full_day': 8,
                'long_day': 10,
                '2_days': 16,
                '3_5_days': 32,
                '1_week_plus': 40,
                '4 hours': 4,
                '8 hours': 8,
                '10 hours': 10,
                '2 days': 16,
                '3-5 days': 32,
                '1 week+': 40
            }
            hours = duration_hours.get(contract.job.duration, 8)
            print(f"   Using mapping: {contract.job.duration} → {hours} hours")
        
        base_payment = float(contract.agreed_rate) * hours
        
        # DEBUG: Log the calculation
        print(f"   Hours calculated: {hours}")
        print(f"   Hours calculated: {hours}")
        print(f"   Rate: ${contract.agreed_rate}")
        print(f"   Base payment: ${base_payment}")
        
        # Check if worker is GST registered
        worker = contract.worker
        worker_gst_registered = worker.gst_registered if worker else False
        
        if worker_gst_registered:
            gst_amount = base_payment * 0.10
            total_payment = base_payment + gst_amount
        else:
            gst_amount = 0
            total_payment = base_payment

        # ✅ UPDATE THIS: Add hours_data and reviews to render_template
        return render_template(
            'contracts/review.html',
            contract=contract,
            hours_data=hours_data,
            reviews=reviews,
            hours=hours,
            base_payment=base_payment,
            gst_amount=gst_amount,
            total_payment=total_payment,
            worker_gst_registered=worker_gst_registered
        )
    
    @app.route('/contracts/<int:contract_id>/closeout')
    @login_required
    def contract_closeout(contract_id):
        """Contract close-out interface"""
        from app.models import Contract
        from app.extensions import db

        contract = Contract.query.get_or_404(contract_id)

        # Security check
        if current_user.id not in [contract.contractor_id, contract.worker_id]:
            flash('You are not authorized to view this contract.', 'error')
            return redirect(url_for('dashboard'))

        # Check if there are time entries before proceeding
        if len(contract.time_entries) == 0:
            flash('You must have at least one time entry before marking the work complete.', 'error')
            return redirect(url_for('contracts_review', contract_id=contract.id))

        # Calculate GST information for display
        from decimal import Decimal
        worker = contract.worker
        worker_gst_registered = worker.gst_registered if worker else False
        
        # Get payment details if available
        payment_list = contract.payments.all()
        base_amount = None
        gst_amount = None
        total_amount = None
        
        if payment_list:
            payment = payment_list[0]
            total_amount = payment.gross_amount
            
            # If worker is GST registered, calculate breakdown
            if worker_gst_registered:
                # Gross amount includes GST, so: gross = base + (base * 0.10) = base * 1.10
                base_amount = total_amount / Decimal('1.10')
                gst_amount = base_amount * Decimal('0.10')
            else:
                base_amount = total_amount
                gst_amount = Decimal('0')

        # If all good, show closeout page
        return render_template('contracts/closeout.html', 
                             contract=contract,
                             worker_gst_registered=worker_gst_registered,
                             base_amount=base_amount,
                             gst_amount=gst_amount,
                             total_amount=total_amount)


    @app.route('/contracts/<int:contract_id>/rate', methods=['GET', 'POST'])
    @login_required
    def rate_contract(contract_id):
            """Rate contract performance (both parties can rate) - USES RATING SERVICE"""
            from app.models.contract import Contract
            from app.services.rating_service import rating_service
            from app.extensions import db

            contract = Contract.query.get_or_404(contract_id)

            # Check authorization using rating service
            eligibility = rating_service.validate_rating_eligibility(contract_id, current_user.id)
            if not eligibility['can_rate']:
                flash(eligibility['error'], 'error')
                return redirect(url_for('contracts_review', contract_id=contract_id))

            if request.method == 'POST':
                try:
                    # Get form data
                    overall_rating = int(request.form.get('overall_rating'))
                    quality_rating = int(request.form.get('quality_rating'))
                    communication_rating = int(request.form.get('communication_rating'))
                    reliability_rating = int(request.form.get('reliability_rating', overall_rating))  # Fallback to overall
                    professionalism_rating = int(request.form.get('professionalism_rating', overall_rating))  # Fallback to overall
                    comment = request.form.get('comment', '').strip()

                    # Validate ratings (1-5 scale)
                    rating_values = [overall_rating, quality_rating, communication_rating, reliability_rating, professionalism_rating]
                    for rating in rating_values:
                        if not (1 <= rating <= 5):
                            flash('All ratings must be between 1 and 5.', 'error')
                            return render_template('contracts/rate.html', contract=contract)

                    # Prepare rating data for service
                    rating_data = {
                        'overall_score': overall_rating,
                        'quality_score': quality_rating,
                        'communication_score': communication_rating,
                        'reliability_score': reliability_rating,
                        'professionalism_score': professionalism_rating,
                        'review_text': comment,
                        'is_public': True  # Default to public
                    }

                    # Use rating service to create rating with all business logic
                    result = rating_service.create_rating(contract_id, current_user.id, rating_data)

                    if result['success']:
                        flash(result['message'], 'success')

                        # Check if both parties have now rated (contract should be completed)
                        db.session.refresh(contract)
                        if contract.status == 'completed':
                            # Both rated - redirect to view ratings
                            return redirect(url_for('view_ratings', contract_id=contract_id))
                        else:
                            # Still waiting for other party - back to contract review with message
                            flash('Thank you for your rating! Waiting for the other party to rate before payment release.', 'info')
                            return redirect(url_for('contracts_review', contract_id=contract_id))
                    else:
                        flash(f'Error submitting rating: {result["error"]}', 'error')
                        return render_template('contracts/rate.html', contract=contract)

                except (ValueError, TypeError) as e:
                    flash('Invalid rating values provided.', 'error')
                    return render_template('contracts/rate.html', contract=contract)
                except Exception as e:
                    flash(f'Error submitting rating: {str(e)}', 'error')
                    return render_template('contracts/rate.html', contract=contract)

            # GET request - show rating form
            # Get payment info to show correct amounts
            payment = contract.payments.first() if contract.payments else None
            return render_template('contracts/rate.html', contract=contract, payment=payment)


    @app.route('/contracts/<int:contract_id>/ratings')
    @login_required
    def view_ratings(contract_id):
        '''View ratings for a completed contract'''
        from app.models.contract import Contract
        from app.models.rating import Rating
        from app.models.user import User

        contract = Contract.query.get_or_404(contract_id)

        if current_user.id not in [contract.contractor_id, contract.worker_id]:
            flash('You do not have access to view these ratings.', 'error')
            return redirect(url_for('dashboard'))

        ratings = Rating.query.filter_by(contract_id=contract_id).all()

        reviews = []
        for rating in ratings:
            reviewer = User.query.get(rating.rater_id)
            reviewee = User.query.get(rating.rated_id)

            reviews.append({
                'reviewer': reviewer,
                'reviewee': reviewee,
                'overall_rating': rating.overall_score,
                'quality_rating': rating.quality_score,
                'communication_rating': rating.communication_score,
                'reliability_rating': rating.reliability_score,
                'professionalism_rating': rating.professionalism_score,
                'safety_rating': rating.professionalism_score,
                'comment': rating.review_text,
                'would_work_again': True
            })

        return render_template('contracts/ratings.html',
                             contract=contract,
                             reviews=reviews)

    @app.route('/payouts')
    @login_required
    def payouts():
            """View payouts for workers"""
            from app.models.contract import Payment, Contract
            from app.extensions import db

            if current_user.role == 'worker':
                # Check onboarding completion for workers
                needs_onboarding, missing_steps = current_user.needs_onboarding()
                if needs_onboarding:
                    if 'profile' in missing_steps:
                        flash('Please complete your profile setup first.', 'warning')
                        return redirect(url_for('onboarding_profile'))
                    elif 'payment' in missing_steps:
                        flash('Please complete your payment setup to receive payments.', 'warning')
                        return redirect(url_for('onboarding_payment'))
                
                # Get all payments for worker's contracts, excluding failed/cancelled ones
                payments = db.session.query(Payment).join(Contract).filter(
                    Contract.worker_id == current_user.id,
                    Payment.status.notin_(['payment_failed', 'cancelled', 'refunded'])
                ).order_by(Payment.date_initiated.desc()).all()

                # Calculate totals - include both 'released' and 'transferred' statuses
                total_earned = sum(p.net_to_worker for p in payments if p.status in ['released', 'transferred'])
                pending_payouts = sum(p.net_to_worker for p in payments if p.status in ['pending', 'held_escrow', 'pending_release'])

                return render_template('payouts/worker.html',
                                     payments=payments,
                                     total_earned=total_earned,
                                     pending_payouts=pending_payouts)

            elif current_user.role == 'contractor':
                # Get all payments for contractor's contracts
                payments = db.session.query(Payment).join(Contract).filter(
                    Contract.contractor_id == current_user.id
                ).order_by(Payment.date_initiated.desc()).all()

                # Calculate totals - include both 'released' and 'transferred' statuses
                total_paid = sum(p.gross_amount for p in payments if p.status in ['released', 'transferred'])
                pending_payments = sum(p.gross_amount for p in payments if p.status in ['pending', 'held_escrow', 'pending_release'])

                return render_template('payouts/contractor.html',
                                     payments=payments,
                                     total_paid=total_paid,
                                     pending_payments=pending_payments)

            else:
                flash('Access denied.', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/payouts/download')
    @login_required
    def download_payouts():
        """Download earnings record as PDF"""
        from app.models.contract import Payment, Contract
        from app.extensions import db
        from flask import Response
        from io import BytesIO
        try:
            from reportlab.lib import colors
            from reportlab.lib.pagesizes import letter, A4
            from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
            from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
            from reportlab.lib.units import inch
            from reportlab.lib.enums import TA_CENTER, TA_RIGHT
        except ImportError:
            flash('PDF generation library not available. Please contact support.', 'error')
            return redirect(url_for('payouts'))
        
        if current_user.role != 'worker':
            flash('Access denied.', 'error')
            return redirect(url_for('dashboard'))
        
        # Get all payments for worker's contracts
        payments = db.session.query(Payment).join(Contract).filter(
            Contract.worker_id == current_user.id
        ).order_by(Payment.date_initiated.desc()).all()
        
        # Calculate totals
        total_earned = sum(float(p.net_to_worker) for p in payments if p.status in ['released', 'transferred'])
        pending_payouts = sum(float(p.net_to_worker) for p in payments if p.status in ['pending', 'held_escrow', 'pending_release'])
        
        # Create PDF in memory
        buffer = BytesIO()
        doc = SimpleDocTemplate(buffer, pagesize=letter, rightMargin=30, leftMargin=30, topMargin=30, bottomMargin=18)
        
        # Container for the 'Flowable' objects
        elements = []
        
        # Define styles
        styles = getSampleStyleSheet()
        title_style = ParagraphStyle(
            'CustomTitle',
            parent=styles['Heading1'],
            fontSize=24,
            textColor=colors.HexColor('#2C3E50'),
            spaceAfter=30,
            alignment=TA_CENTER
        )
        
        heading_style = ParagraphStyle(
            'CustomHeading',
            parent=styles['Heading2'],
            fontSize=14,
            textColor=colors.HexColor('#34495E'),
            spaceAfter=12
        )
        
        # Title
        title = Paragraph("Earnings Record", title_style)
        elements.append(title)
        
        # Worker info
        worker_name = f"{current_user.first_name} {current_user.last_name}" if current_user.first_name else current_user.username
        info_data = [
            ['Worker:', worker_name],
            ['Email:', current_user.email],
            ['Generated:', datetime.now().strftime('%Y-%m-%d %H:%M:%S')],
            ['Total Records:', str(len(payments))]
        ]
        
        info_table = Table(info_data, colWidths=[1.5*inch, 4*inch])
        info_table.setStyle(TableStyle([
            ('FONT', (0, 0), (0, -1), 'Helvetica-Bold'),
            ('FONT', (1, 0), (1, -1), 'Helvetica'),
            ('FONTSIZE', (0, 0), (-1, -1), 10),
            ('TEXTCOLOR', (0, 0), (-1, -1), colors.HexColor('#2C3E50')),
            ('ALIGN', (0, 0), (0, -1), 'RIGHT'),
            ('ALIGN', (1, 0), (1, -1), 'LEFT'),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
        ]))
        elements.append(info_table)
        elements.append(Spacer(1, 20))
        
        # Summary section
        summary_heading = Paragraph("Summary", heading_style)
        elements.append(summary_heading)
        
        summary_data = [
            ['Total Earned (Released/Transferred):', f'${total_earned:,.2f} AUD'],
            ['Pending Payouts:', f'${pending_payouts:,.2f} AUD']
        ]
        
        summary_table = Table(summary_data, colWidths=[3.5*inch, 2*inch])
        summary_table.setStyle(TableStyle([
            ('FONT', (0, 0), (0, -1), 'Helvetica-Bold'),
            ('FONT', (1, 0), (1, -1), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, -1), 11),
            ('TEXTCOLOR', (0, 0), (0, 0), colors.HexColor('#27AE60')),
            ('TEXTCOLOR', (1, 0), (1, 0), colors.HexColor('#27AE60')),
            ('TEXTCOLOR', (0, 1), (0, 1), colors.HexColor('#F39C12')),
            ('TEXTCOLOR', (1, 1), (1, 1), colors.HexColor('#F39C12')),
            ('ALIGN', (0, 0), (0, -1), 'RIGHT'),
            ('ALIGN', (1, 0), (1, -1), 'RIGHT'),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 8),
            ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor('#ECF0F1')),
            ('BOX', (0, 0), (-1, -1), 1, colors.HexColor('#BDC3C7')),
        ]))
        elements.append(summary_table)
        elements.append(Spacer(1, 30))
        
        # Payment history
        history_heading = Paragraph("Payment History", heading_style)
        elements.append(history_heading)
        
        # Table data
        data = [['Ref', 'Date', 'Gross', 'Fee', 'Net', 'Status']]
        
        for payment in payments:
            status_text = payment.status.replace('_', ' ').title() if payment.status else 'N/A'
            data.append([
                payment.payment_reference or 'N/A',
                payment.date_initiated.strftime('%Y-%m-%d') if payment.date_initiated else 'N/A',
                f'${float(payment.gross_amount):.2f}' if payment.gross_amount else '$0.00',
                f'${float(payment.platform_fee):.2f}' if payment.platform_fee else '$0.00',
                f'${float(payment.net_to_worker):.2f}' if payment.net_to_worker else '$0.00',
                status_text
            ])
        
        # Create table
        table = Table(data, colWidths=[1.2*inch, 1*inch, 0.9*inch, 0.9*inch, 1*inch, 1.5*inch])
        
        # Style the table
        table.setStyle(TableStyle([
            # Header styling
            ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#3498DB')),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
            ('ALIGN', (0, 0), (-1, 0), 'CENTER'),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, 0), 10),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
            
            # Data styling
            ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
            ('FONTSIZE', (0, 1), (-1, -1), 8),
            ('ALIGN', (2, 1), (4, -1), 'RIGHT'),
            ('ALIGN', (0, 1), (1, -1), 'LEFT'),
            ('ALIGN', (5, 1), (5, -1), 'CENTER'),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
            ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#F8F9FA')]),
            ('TOPPADDING', (0, 1), (-1, -1), 6),
            ('BOTTOMPADDING', (0, 1), (-1, -1), 6),
        ]))
        
        elements.append(table)
        
        # Build PDF
        doc.build(elements)
        
        # Get the value of the BytesIO buffer and prepare response
        pdf_data = buffer.getvalue()
        buffer.close()
        
        # Generate filename with current date
        filename = f"earnings_record_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
        
        return Response(
            pdf_data,
            mimetype='application/pdf',
            headers={'Content-Disposition': f'attachment; filename={filename}'}
        )

        # PHASE 1: BLUEPRINT PREFIX FIXES
    @app.route('/messages')
    @login_required
    def messages_wrapper():
            """Messages interface - connects to existing API"""
            from app.models import User
            from app.extensions import db

            # Get user's conversations
            try:
                # This connects to existing messaging functionality
                return render_template('messages/chat.html',
                                     current_user=current_user,
                                     conversations=[])
            except Exception as e:
                flash('Messages temporarily unavailable.', 'warning')
                return redirect(url_for('dashboard'))

    @app.route('/messages/<int:message_id>')
    @login_required
    def message_view_by_id(message_id):
            """View specific message by ID - redirects to conversation with sender"""
            try:
                from app.models.message import Message
                from app.extensions import db

                # Find the message
                message = Message.query.get_or_404(message_id)

                # Verify current user is sender or receiver
                if current_user.id not in [message.sender_id, message.receiver_id]:
                    flash('You do not have access to this message.', 'error')
                    return redirect(url_for('messages_wrapper'))

                # Determine the other user ID (who to have conversation with)
                other_user_id = message.sender_id if current_user.id == message.receiver_id else message.receiver_id

                # Mark message as read if current user is the receiver
                if current_user.id == message.receiver_id and not message.read_at:
                    from app.services.message_service import message_service
                    message_service.mark_message_as_read(message_id, current_user.id)

                # Redirect to conversation with the other user
                return redirect(url_for('messages_view', user_id=other_user_id))

            except Exception as e:
                logger.error(f"Error accessing message {message_id}: {e}")
                flash('Message not found.', 'error')
                return redirect(url_for('messages_wrapper'))

    @app.route('/messages/view')
    @login_required
    def messages_view():
            """Contract-context messaging view with bidirectional support"""
            from app.models import User, Contract
            from app.extensions import db

            try:
                # Get URL parameters for contract context
                contract_id = request.args.get('contract_id', type=int)
                user_id = request.args.get('user_id', type=int)

                # Initialize variables
                contract = None
                other_user = None

                # Validate contract context if provided
                if contract_id:
                    contract = Contract.query.get_or_404(contract_id)

                    # Verify current user is party to this contract
                    if current_user.id not in [contract.contractor_id, contract.worker_id]:
                        flash('You do not have access to this contract.', 'error')
                        return redirect(url_for('dashboard'))

                # Validate target user if provided
                if user_id:
                    other_user = User.query.get_or_404(user_id)

                    # Verify user access - if contract context exists, verify the target user is the other party
                    if contract:
                        expected_user_id = contract.worker_id if current_user.id == contract.contractor_id else contract.contractor_id
                        if user_id != expected_user_id:
                            flash('Invalid user for this contract.', 'error')
                            return redirect(url_for('dashboard'))

                # Render messaging interface with contract context
                return render_template('messages/chat.html',
                                     current_user=current_user,
                                     contract=contract,
                                     other_user=other_user,
                                     conversations=[],
                                     contract_context=True)

            except Exception as e:
                flash(f'Error accessing messages: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/notifications')
    @login_required
    def notifications_wrapper():
            """Notifications interface - connects to existing API"""
            try:
                # Get user's notifications from notification service
                notifications = notification_service.get_user_notifications(
                    user_id=current_user.id,
                    limit=50,  # Show recent 50 notifications
                    offset=0,
                    unread_only=False
                )

                # Get unread count for badge
                unread_count = notification_service.get_unread_count(current_user.id)

                print(f"[NOTIFICATION DEBUG] Found {len(notifications)} notifications for user {current_user.id}")
                print(f"[NOTIFICATION DEBUG] Unread count: {unread_count}")

                return render_template('notifications/list.html',
                                     notifications=notifications,
                                     unread_count=unread_count)
            except Exception as e:
                print(f"[NOTIFICATION ERROR] Error loading notifications: {e}")
                flash('Notifications temporarily unavailable.', 'warning')
                return redirect(url_for('dashboard'))

        # PHASE 2: CORE USER WORKFLOW ROUTES
    @app.route('/jobs/employer')
    @login_required
    def jobs_employer():
            """Employer job management dashboard"""
            from app.models import Job

            if current_user.role not in ['contractor', 'employer']:
                flash('Access denied. Employer access required.', 'error')
                return redirect(url_for('dashboard'))

            try:
                user_jobs = Job.query.filter_by(contractor_id=current_user.id).order_by(Job.date_posted.desc()).all()
                return render_template('jobs/employer_jobs.html', jobs=user_jobs)
            except Exception as e:
                flash(f'Error loading jobs: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/jobs/worker')
    @login_required
    def jobs_worker():
            """Worker job discovery and applications"""
            from app.models import Job, Application
            from app.extensions import db

            if current_user.role != 'worker':
                flash('Access denied. Worker access required.', 'error')
                return redirect(url_for('dashboard'))

            # Check onboarding completion for workers
            needs_onboarding, missing_steps = current_user.needs_onboarding()
            if needs_onboarding:
                if 'profile' in missing_steps:
                    flash('Please complete your profile setup before browsing jobs.', 'warning')
                    return redirect(url_for('onboarding_profile'))
                elif 'payment' in missing_steps:
                    flash('Please complete your payment setup before browsing jobs.', 'warning')
                    return redirect(url_for('onboarding_payment'))

            try:
                # Get jobs suitable for worker (exclude those already applied to)
                applied_job_ids = db.session.query(Application.job_id).filter_by(worker_id=current_user.id).subquery()
                available_jobs = Job.query.filter(
                    Job.status == 'open',
                    ~Job.id.in_(applied_job_ids)
                ).order_by(Job.date_posted.desc()).all()

                return render_template('jobs/worker_jobs.html', jobs=available_jobs)
            except Exception as e:
                flash(f'Error loading jobs: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/applications/received')
    @login_required
    def applications_received():
            """Employer application management"""
            from app.models import Application, Job
            from app.extensions import db

            if current_user.role not in ['contractor', 'employer']:
                flash('Access denied. Employer access required.', 'error')
                return redirect(url_for('dashboard'))

            try:
                # Build base query
                query = db.session.query(Application).join(Job).filter(
                    Job.contractor_id == current_user.id
                )

                # Apply job_id filter if provided
                job_id = request.args.get('job_id')
                if job_id:
                    try:
                        job_id = int(job_id)
                        query = query.filter(Job.id == job_id)
                    except (TypeError, ValueError):
                        flash('Invalid job ID provided', 'error')

                # Execute query with ordering
                received_applications = query.order_by(Application.date_applied.desc()).all()

                return render_template('applications/contractor_list.html', applications=received_applications)
            except Exception as e:
                flash(f'Error loading applications: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/settings', methods=['GET', 'POST'])
    @login_required
    def user_settings():
            """User settings and preferences"""
            if request.method == 'POST':
                try:
                    # Determine which form was submitted
                    form_type = request.form.get('form_type')
                    
                    if form_type == 'notifications':
                        # Update notification preferences
                        current_user.preferences['notifications'] = {
                            'email_job_alerts': 'email_job_alerts' in request.form,
                            'email_applications': 'email_applications' in request.form,
                            'email_contracts': 'email_contracts' in request.form,
                            'email_payments': 'email_payments' in request.form
                        }
                        # Flag the column as modified for SQLAlchemy to detect the change
                        from sqlalchemy.orm.attributes import flag_modified
                        flag_modified(current_user, 'preferences')
                        db.session.commit()
                        flash('Notification preferences updated successfully!', 'success')
                    
                    elif form_type == 'privacy':
                        # Update privacy settings
                        current_user.preferences['privacy'] = {
                            'profile_public': 'profile_public' in request.form,
                            'contact_info_visible': 'contact_info_visible' in request.form,
                            'rating_visible': 'rating_visible' in request.form,
                            'job_history_visible': 'job_history_visible' in request.form
                        }
                        # Flag the column as modified for SQLAlchemy to detect the change
                        from sqlalchemy.orm.attributes import flag_modified
                        flag_modified(current_user, 'preferences')
                        db.session.commit()
                        flash('Privacy settings updated successfully!', 'success')
                    
                    return redirect(url_for('user_settings'))
                    
                except Exception as e:
                    db.session.rollback()
                    flash(f'Error updating settings: {str(e)}', 'error')
                    return redirect(url_for('user_settings'))
            
            # Check if Stripe account is still valid
            stripe_account_valid = False
            if current_user.stripe_account_id:
                try:
                    from app.services.stripe_service import stripe_service
                    import stripe
                    account = stripe.Account.retrieve(current_user.stripe_account_id)
                    stripe_account_valid = True
                except Exception as e:
                    # Account no longer exists or is invalid
                    app.logger.warning(f"Stripe account {current_user.stripe_account_id} is invalid: {e}")
                    # Clear the invalid account info
                    current_user.stripe_account_id = None
                    current_user.stripe_onboarding_complete = False
                    current_user.stripe_payouts_enabled = False
                    db.session.commit()
                    stripe_account_valid = False
            
            return render_template('auth/settings.html', user=current_user, stripe_account_valid=stripe_account_valid)

    @app.route('/settings/delete-account', methods=['POST'])
    @login_required
    def delete_my_account():
            """Allow user to delete their own account (soft delete with anonymisation)"""
            from app.services.user_deletion_service import UserDeletionService
            
            try:
                # Verify email confirmation from request
                data = request.get_json()
                confirmed_email = data.get('email', '').strip().lower()
                
                if confirmed_email != current_user.email.lower():
                    return jsonify({
                        'success': False,
                        'message': 'Email confirmation does not match your account email.'
                    }), 400
                
                user_id = current_user.id
                
                # Log out the user before deletion
                logout_user()
                
                # Perform soft delete with anonymisation
                success, message = UserDeletionService.soft_delete_user(
                    user_id=user_id,
                    deleted_by_admin=False
                )
                
                if success:
                    return jsonify({
                        'success': True,
                        'message': 'Your account has been deleted and anonymised. A confirmation email has been sent. Transaction records will be retained for 7 years for tax compliance.',
                        'redirect': '/'
                    })
                else:
                    return jsonify({
                        'success': False,
                        'message': message
                    }), 400
                
            except Exception as e:
                current_app.logger.error(f'Error deleting account: {str(e)}')
                return jsonify({
                    'success': False,
                    'message': 'An error occurred while deleting your account. Please contact support.'
                }), 500

        # PHASE 3: CONTRACT MANAGEMENT ROUTES
    @app.route('/contracts/pending')
    @login_required
    def contracts_pending():
            """Contracts awaiting signature"""
            from app.models import Contract

            try:
                pending_contracts = Contract.query.filter_by(
                    status='pending_agreement'
                ).filter(
                    (Contract.contractor_id == current_user.id) |
                    (Contract.worker_id == current_user.id)
                ).order_by(Contract.created_at.desc()).all()

                return render_template('contracts/list.html',
                                   contracts=pending_contracts,
                                   filter_type='pending',
                                   title='Pending Contracts')
            except Exception as e:
                flash(f'Error loading pending contracts: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/contracts/active')
    @login_required
    def contracts_active():
            """Active contracts in progress"""
            from app.models import Contract

            try:
                active_contracts = Contract.query.filter_by(
                    status='active'
                ).filter(
                    (Contract.contractor_id == current_user.id) |
                    (Contract.worker_id == current_user.id)
                ).order_by(Contract.created_at.desc()).all()

                return render_template('contracts/list.html',
                                   contracts=active_contracts,
                                   filter_type='active',
                                   title='Active Contracts')
            except Exception as e:
                flash(f'Error loading active contracts: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/contracts/completed')
    @login_required
    def contracts_completed():
            """Completed contract history"""
            from app.models import Contract

            try:
                completed_contracts = Contract.query.filter_by(
                    status='completed'
                ).filter(
                    (Contract.contractor_id == current_user.id) |
                    (Contract.worker_id == current_user.id)
                ).order_by(Contract.created_at.desc()).all()

                return render_template('contracts/list.html',
                                   contracts=completed_contracts,
                                   filter_type='completed',
                                   title='Completed Contracts')
            except Exception as e:
                flash(f'Error loading completed contracts: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/contracts/needs-rating')
    @login_required
    def contracts_needs_rating():
            """Contracts needing rating/review"""
            from app.models import Contract

            try:
                rating_contracts = Contract.query.filter_by(
                    status='pending_rating'
                ).filter(
                    (Contract.contractor_id == current_user.id) |
                    (Contract.worker_id == current_user.id)
                ).order_by(Contract.created_at.desc()).all()

                return render_template('contracts/list.html',
                                   contracts=rating_contracts,
                                   filter_type='needs_rating',
                                   title='Contracts Needing Rating')
            except Exception as e:
                flash(f'Error loading contracts needing rating: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

        # PHASE 4: FINANCIAL MANAGEMENT ROUTES
    @app.route('/payments')
    @login_required
    def payments_history():
            """Payment history and management"""
            from app.models.contract import Payment, Contract
            from app.extensions import db

            try:
                if current_user.role in ['contractor', 'employer']:
                    # Get payments made by contractor
                    payments = db.session.query(Payment).join(Contract).filter(
                        Contract.contractor_id == current_user.id
                    ).order_by(Payment.date_initiated.desc()).all()

                    # Calculate totals
                    total_paid = sum(p.gross_amount for p in payments if p.status == 'released')
                    pending_payments = sum(p.gross_amount for p in payments if p.status in ['pending', 'held_escrow'])

                    return render_template('payments/history.html',
                                         payments=payments,
                                         total_paid=total_paid,
                                         pending_payments=pending_payments)
                else:
                    flash('Access denied.', 'error')
                    return redirect(url_for('dashboard'))
            except Exception as e:
                flash(f'Error loading payments: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/payments/pending')
    @login_required
    def payments_pending():
            """Outstanding payments"""
            from app.models.contract import Payment, Contract
            from app.extensions import db
            from datetime import datetime

            try:
                if current_user.role in ['contractor', 'employer']:
                    pending_payments = db.session.query(Payment).join(Contract).filter(
                        Contract.contractor_id == current_user.id,
                        Payment.status.in_(['pending', 'held_escrow'])
                    ).order_by(Payment.date_initiated.desc()).all()

                    return render_template('payments/pending.html', 
                                         payments=pending_payments,
                                         current_date=datetime.utcnow().date())
                else:
                    flash('Access denied.', 'error')
                    return redirect(url_for('dashboard'))
            except Exception as e:
                flash(f'Error loading pending payments: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/payouts/pending')
    @login_required
    def payouts_pending():
            """Pending contractor payouts"""
            from app.models.contract import Payment, Contract
            from app.extensions import db

            try:
                if current_user.role == 'worker':
                    pending_payouts = db.session.query(Payment).join(Contract).filter(
                        Contract.worker_id == current_user.id,
                        Payment.status.in_(['pending', 'held_escrow', 'pending_release'])
                    ).order_by(Payment.date_initiated.desc()).all()

                    pending_count = len(pending_payouts)
                    current_date = datetime.now().date()

                    return render_template('payouts/pending.html', 
                                         payouts=pending_payouts,
                                         pending_count=pending_count,
                                         current_date=current_date)
                else:
                    flash('Access denied.', 'error')
                    return redirect(url_for('dashboard'))
            except Exception as e:
                flash(f'Error loading pending payouts: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/invoices')
    @login_required
    def invoices_list():
            """Invoice generation and management"""
            from app.models import Invoice, Payment, Contract

            try:
                # Get invoices where user is the contractor
                contractor_invoices = Invoice.query.filter(
                    Invoice.contractor_id == current_user.id
                ).all()
                
                # Get invoices where user is the worker (through payment -> contract)
                worker_invoices = Invoice.query.join(Payment).join(Contract).filter(
                    Contract.worker_id == current_user.id
                ).all()
                
                # Combine and order by created_at
                user_invoices = list(set(contractor_invoices + worker_invoices))
                user_invoices.sort(key=lambda x: x.created_at, reverse=True)

                return render_template('invoices/list.html', invoices=user_invoices)
            except Exception as e:
                flash(f'Error loading invoices: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/contracts/<int:contract_id>/payment/return')
    @login_required
    def payment_return_handler(contract_id):
            """Handle return from 3D Secure authentication"""
            from app.models import Contract
            
            try:
                contract = Contract.query.get_or_404(contract_id)
                
                # Verify access
                if contract.contractor_id != current_user.id:
                    flash('Access denied.', 'error')
                    return redirect(url_for('dashboard'))
                
                # Redirect back to contract review page
                flash('Payment authentication completed. Please check payment status.', 'info')
                return redirect(url_for('contracts_review', contract_id=contract_id))
                
            except Exception as e:
                flash(f'Error processing payment return: {str(e)}', 'error')
                return redirect(url_for('dashboard'))

    @app.route('/contracts/<int:contract_id>/payment')
    @login_required
    def contract_payment_form(contract_id):
            """Secure Stripe Elements payment form for contract"""
            from app.models import Contract, Payment
            from flask import current_app

            try:
                # Get contract and verify access
                contract = Contract.query.get_or_404(contract_id)

                # Only contractor can make payments
                if contract.contractor_id != current_user.id:
                    flash('Only the contract owner can make payments.', 'error')
                    return redirect(url_for('contracts_review', contract_id=contract_id))

                # Payment can be made before or after signing - it's required before contract activation
                # Removed the signing requirement to allow upfront payment

                # Check if payment already exists
                existing_payment = Payment.query.filter(
                    Payment.contract_id == contract.id,
                    Payment.status.in_(['pending_payment', 'held_escrow', 'pending_release'])
                ).first()

                if existing_payment:
                    flash('Payment already exists for this contract.', 'warning')
                    return redirect(url_for('contracts_review', contract_id=contract_id))

                # Calculate payment amount based on job duration
                # Try to parse duration as numeric hours first (new format)
                try:
                    hours = int(contract.job.duration)
                except (ValueError, TypeError):
                    # Legacy format - use mapping
                    # Duration mapping: half_day=4hrs, full_day=8hrs, long_day=10hrs, 2_days=16hrs, 3_5_days=32hrs, 1_week_plus=40hrs
                    # Also support legacy formats for backwards compatibility
                    duration_hours = {
                        'half_day': 4,
                        'full_day': 8,
                        'long_day': 10,
                        '2_days': 16,
                        '3_5_days': 32,
                        '1_week_plus': 40,
                        '4 hours': 4,
                        '8 hours': 8,
                        '10 hours': 10,
                        '2 days': 16,
                        '3-5 days': 32,
                        '1 week+': 40
                    }
                    hours = duration_hours.get(contract.job.duration, 8)  # Default to 8 hours if not specified
                
                # Calculate payment amount
                base_payment_amount = float(contract.agreed_rate) * hours
                
                # Add GST if worker is GST registered
                worker = contract.worker
                if worker and worker.gst_registered:
                    gst_amount = base_payment_amount * 0.10
                    total_payment_amount = base_payment_amount + gst_amount
                else:
                    gst_amount = 0
                    total_payment_amount = base_payment_amount

                # Get Stripe publishable key
                stripe_publishable_key = current_app.config.get('STRIPE_PUBLISHABLE_KEY')
                if not stripe_publishable_key:
                    flash('Payment system not configured. Please contact support.', 'error')
                    return redirect(url_for('contracts_review', contract_id=contract_id))

                # Using Flask-Login session authentication - no JWT token needed
                return render_template('payments/payment_form.html',
                                     contract=contract,
                                     payment_amount=total_payment_amount,
                                     base_amount=base_payment_amount,
                                     gst_amount=gst_amount,
                                     worker_gst_registered=worker.gst_registered if worker else False,
                                     stripe_publishable_key=stripe_publishable_key,
                                     current_user=current_user)

            except Exception as e:
                logger.error(f"Error loading payment form for contract {contract_id}: {e}")
                flash('Error loading payment form.', 'error')
                return redirect(url_for('contracts_review', contract_id=contract_id))

        # PHASE 5: PROFILE MANAGEMENT ROUTES
    @app.route('/profile/edit', methods=['GET', 'POST'])
    @login_required
    def profile_edit():
            """Profile editing interface"""
            if request.method == 'POST':
                from app.extensions import db
                
                try:
                    # Update basic information
                    current_user.first_name = request.form.get('first_name')
                    current_user.last_name = request.form.get('last_name')
                    current_user.email = request.form.get('email')
                    current_user.phone_number = request.form.get('phone_number')
                    current_user.location = request.form.get('location')
                    current_user.abn_number = request.form.get('abn_number')
                    
                    # Update primary_trade for workers
                    if current_user.role == 'worker' and 'primary_trade' in request.form:
                        selected_trades = request.form.getlist('primary_trade')
                        if selected_trades:
                            # Store as comma-separated string (max 3)
                            current_user.primary_trade = ','.join(selected_trades[:3])
                        else:
                            current_user.primary_trade = None
                    
                    # Update secondary_trade for workers
                    if current_user.role == 'worker' and 'secondary_trade' in request.form:
                        selected_secondary_trades = request.form.getlist('secondary_trade')
                        if selected_secondary_trades:
                            # Store as comma-separated string (no limit)
                            current_user.secondary_trade = ','.join(selected_secondary_trades)
                        else:
                            current_user.secondary_trade = None
                    
                    # Update role-specific fields
                    if current_user.role == 'worker':
                        if 'skills' in request.form:
                            current_user.skills = request.form.get('skills')
                        if 'hourly_rate' in request.form and request.form.get('hourly_rate'):
                            current_user.hourly_rate = float(request.form.get('hourly_rate'))
                        if 'experience_years' in request.form and request.form.get('experience_years'):
                            current_user.experience_years = int(request.form.get('experience_years'))
                    
                    if current_user.role == 'contractor':
                        if 'company_description' in request.form:
                            current_user.company_description = request.form.get('company_description')
                    
                    # Update insurance information
                    current_user.public_liability_insurance = 'public_liability_insurance' in request.form
                    current_user.workers_comp_insurance = 'workers_compensation' in request.form
                    
                    db.session.commit()
                    flash('Profile updated successfully!', 'success')
                    return redirect(url_for('profile'))
                    
                except Exception as e:
                    db.session.rollback()
                    flash(f'Error updating profile: {str(e)}', 'error')
                    from app.models.category import Category
                    categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
                    return render_template('profile/edit.html', user=current_user, categories=categories)
            
            from app.models.category import Category
            categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()
            return render_template('profile/edit.html', user=current_user, categories=categories)

    @app.route('/profile/verification')
    @login_required
    def profile_verification():
            """Document verification system"""
            return render_template('profile/verification.html', user=current_user)

    @app.route('/profile/insurance')
    @login_required
    def profile_insurance():
            """Insurance management"""
            return render_template('profile/insurance.html', user=current_user)

    @app.route('/api/upload-profile-picture', methods=['POST'])
    @login_required
    def upload_profile_picture():
            """Upload profile picture to Cloudinary and update user record"""
            try:
                import cloudinary
                import cloudinary.uploader
                from app.extensions import db
                
                # Configure Cloudinary
                cloudinary.config(
                    cloud_name=app.config.get('CLOUDINARY_CLOUD_NAME'),
                    api_key=app.config.get('CLOUDINARY_API_KEY'),
                    api_secret=app.config.get('CLOUDINARY_API_SECRET')
                )
                
                # Check if file was uploaded
                if 'profile_picture' not in request.files:
                    return jsonify({'success': False, 'message': 'No file uploaded'}), 400
                
                file = request.files['profile_picture']
                
                if file.filename == '':
                    return jsonify({'success': False, 'message': 'No file selected'}), 400
                
                # Validate file type
                allowed_extensions = {'jpg', 'jpeg', 'png'}
                file_ext = file.filename.rsplit('.', 1)[1].lower() if '.' in file.filename else ''
                
                if file_ext not in allowed_extensions:
                    return jsonify({'success': False, 'message': 'Invalid file type. Only JPG and PNG allowed'}), 400
                
                # Upload to Cloudinary
                upload_result = cloudinary.uploader.upload(
                    file,
                    folder='rateright/profile_pictures',
                    public_id=f'user_{current_user.id}',
                    overwrite=True,
                    transformation=[
                        {'width': 400, 'height': 400, 'crop': 'fill', 'gravity': 'face'},
                        {'quality': 'auto', 'fetch_format': 'auto'}
                    ]
                )
                
                # Get secure URL
                image_url = upload_result.get('secure_url')
                
                # Update user's profile picture
                current_user.profile_picture = image_url
                db.session.commit()
                
                return jsonify({
                    'success': True,
                    'url': image_url,
                    'message': 'Profile picture uploaded successfully'
                }), 200
                
            except Exception as e:
                print(f"Error uploading profile picture: {str(e)}")
                return jsonify({
                    'success': False,
                    'message': f'Upload failed: {str(e)}'
                }), 500

        # STRIPE CONNECT ROUTES
    @app.route('/api/stripe/setup-payouts')
    @login_required
    def stripe_setup_payouts():
            """Initialize Stripe Connect onboarding for payouts"""
            import os
            from app.services.stripe_service import stripe_service
            from app.extensions import db
            from flask import url_for

            try:
                # Check if user already has Stripe account
                if current_user.stripe_account_id:
                    # Get account status
                    account_status = stripe_service.get_account_status(current_user.stripe_account_id)

                    if account_status['charges_enabled'] and account_status['payouts_enabled']:
                        flash('Your payout account is already set up and active!', 'success')
                        return redirect(url_for('user_settings'))

                    # Account exists but needs completion
                    account_id = current_user.stripe_account_id
                else:
                    # Create new Stripe Connect account
                    user_data = {
                        'email': current_user.email,
                        'first_name': current_user.first_name,
                        'last_name': current_user.last_name
                    }

                    account = stripe_service.create_connect_account(user_data)
                    account_id = account.id

                    # Save account ID to user
                    current_user.stripe_account_id = account_id
                    db.session.commit()

                # Create onboarding link
                from flask import request
                
                # Determine if we're in production (Fly.io) or local development
                is_production = os.environ.get('FLY_APP_NAME') is not None
                stripe_secret_key = current_app.config.get('STRIPE_SECRET_KEY', '')
                is_live_mode = stripe_secret_key.startswith('sk_live_')
                
                # Build the base URL with proper protocol
                if is_production or is_live_mode:
                    # Production or live mode: Always use HTTPS
                    # Use request.host instead of host_url to avoid protocol issues with proxies
                    base_url = f"https://{request.host}"
                else:
                    # Local development with test keys: Can use HTTP
                    base_url = request.host_url.rstrip('/')
                
                return_url = f"{base_url}/api/stripe/onboarding/return"
                refresh_url = f"{base_url}/api/stripe/onboarding/refresh"
                
                app.logger.info(f"Stripe onboarding URLs - Return: {return_url}, Refresh: {refresh_url}")

                onboarding_link = stripe_service.create_onboarding_link(
                    account_id,
                    return_url,
                    refresh_url
                )

                # Redirect to Stripe hosted onboarding
                return redirect(onboarding_link.url)

            except Exception as e:
                import traceback
                error_details = traceback.format_exc()
                app.logger.error(f"Stripe Connect setup error: {str(e)}")
                app.logger.error(f"Full traceback: {error_details}")
                
                # Check for specific error types and provide helpful messages
                error_msg = str(e).lower()
                if 'platform-profile' in error_msg or 'managing losses' in error_msg:
                    flash('Stripe Connect not configured. Please complete your Stripe platform profile at https://dashboard.stripe.com/settings/connect/platform-profile', 'error')
                elif 'https' in error_msg and 'livemode' in error_msg:
                    flash('Stripe live mode requires HTTPS. For local testing, use test mode keys (pk_test_/sk_test_) or test on your production server.', 'error')
                else:
                    flash(f'Error setting up payouts: {str(e)}', 'error')
                return redirect(url_for('user_settings'))

    @app.route('/api/stripe/onboarding/return')
    @login_required
    def stripe_onboarding_return():
            """Handle return from Stripe onboarding"""
            from app.services.stripe_service import stripe_service
            from app.extensions import db

            try:
                if current_user.stripe_account_id:
                    # Check account status
                    account_status = stripe_service.get_account_status(current_user.stripe_account_id)

                    # Update user record
                    current_user.stripe_onboarding_complete = account_status['details_submitted']
                    current_user.stripe_payouts_enabled = account_status['payouts_enabled']
                    current_user.stripe_charges_enabled = account_status['charges_enabled']

                    db.session.commit()

                    if account_status['payouts_enabled']:
                        flash('Payout setup completed successfully! You can now receive payments.', 'success')
                    elif account_status['details_submitted']:
                        flash('Account information submitted. Stripe is reviewing your details.', 'info')
                    else:
                        flash('Setup incomplete. Please complete all required information.', 'warning')
                else:
                    flash('Account setup error. Please try again.', 'error')

            except Exception as e:
                app.logger.error(f"Stripe onboarding return error: {str(e)}")
                flash('Error checking account status.', 'error')

            return redirect(url_for('user_settings'))

    @app.route('/api/stripe/onboarding/refresh')
    @login_required
    def stripe_onboarding_refresh():
            """Handle refresh/restart of Stripe onboarding"""
            # Redirect back to setup
            return redirect(url_for('stripe_setup_payouts'))

    @app.route('/api/stripe/dashboard')
    @login_required
    def stripe_dashboard():
            """Redirect to Stripe Express dashboard"""
            from app.services.stripe_service import stripe_service

            try:
                if not current_user.stripe_account_id:
                    flash('Please set up your payout account first.', 'warning')
                    return redirect(url_for('user_settings'))

                # Create dashboard login link
                dashboard_link = stripe_service.create_dashboard_link(current_user.stripe_account_id)

                # Redirect to Stripe dashboard
                return redirect(dashboard_link.url)

            except Exception as e:
                app.logger.error(f"Stripe dashboard error: {str(e)}")
                flash('Error accessing dashboard. Please try again later.', 'error')
                return redirect(url_for('user_settings'))

        # ==================== TIME TRACKING ROUTES ====================

    @app.route('/contracts/<int:contract_id>/hours')
    @login_required
    def contract_hours_view(contract_id):
            """View contract time tracking data"""
            from app.services.time_tracking_service import time_tracking_service
            from app.models import Contract

            try:
                # Verify user has access to this contract
                contract = Contract.query.get_or_404(contract_id)
                if current_user.id not in [contract.contractor_id, contract.worker_id]:
                    flash('You do not have access to this contract.', 'error')
                    return redirect(url_for('dashboard'))

                # Get contract hours data
                hours_data = time_tracking_service.get_contract_hours(contract_id)

                if not hours_data.get('success'):
                    flash(f"Error loading hours: {hours_data.get('error')}", 'error')
                    return redirect(url_for('contracts_review', contract_id=contract_id))

                return render_template('contracts/hours.html',
                                     contract=contract,
                                     hours_data=hours_data)

            except Exception as e:
                logger.error(f"Error viewing contract hours {contract_id}: {e}")
                #flash('Error loading time tracking data.', 'error')
                return redirect(url_for('contracts_review', contract_id=contract_id))

    @app.route('/contracts/<int:contract_id>/hours/edit', methods=['GET', 'POST'])
    @login_required
    def contract_hours_edit(contract_id):
            """Edit contract hours (fixes user issue!)"""
            from app.services.time_tracking_service import time_tracking_service
            from app.models import Contract
            from datetime import date

            try:
                # Verify user has access to this contract
                contract = Contract.query.get_or_404(contract_id)
                if current_user.id not in [contract.contractor_id, contract.worker_id]:
                    flash('You do not have access to this contract.', 'error')
                    return redirect(url_for('dashboard'))

                if request.method == 'POST':
                    action = request.form.get('action')

                    if action == 'add_hours':
                        # Add new time entry
                        hours = request.form.get('hours', type=float)
                        work_date_str = request.form.get('work_date')
                        description = request.form.get('description', '')
                        location = request.form.get('location', '')

                        # Parse date
                        try:
                            work_date = date.fromisoformat(work_date_str) if work_date_str else date.today()
                        except ValueError:
                            flash('Invalid work date format.', 'error')
                            return redirect(url_for('contract_hours_edit', contract_id=contract_id))

                        # Validate hours
                        if not hours or hours <= 0:
                            flash('Hours must be greater than 0.', 'error')
                            return redirect(url_for('contract_hours_edit', contract_id=contract_id))

                        # Create time entry
                        result = time_tracking_service.create_time_entry(
                            contract_id=contract_id,
                            worker_id=contract.worker_id,
                            hours=hours,
                            work_date=work_date,
                            description=description,
                            location=location
                        )

                        if result.get('success'):
                            flash(result.get('message'), 'success')
                        else:
                            flash(f"Error adding hours: {result.get('error')}", 'error')

                    elif action == 'edit_entry':
                        # Edit existing time entry
                        entry_id = request.form.get('entry_id', type=int)
                        hours = request.form.get('hours', type=float)
                        description = request.form.get('description')
                        location = request.form.get('location')

                        if not entry_id:
                            flash('Entry ID is required for editing.', 'error')
                            return redirect(url_for('contract_hours_edit', contract_id=contract_id))

                        result = time_tracking_service.edit_time_entry(
                            entry_id=entry_id,
                            hours=hours,
                            description=description,
                            location=location,
                            user_id=current_user.id
                        )

                        if result.get('success'):
                            flash(result.get('message'), 'success')
                        else:
                            flash(f"Error editing hours: {result.get('error')}", 'error')

                    elif action == 'delete_entry':
                        # Delete time entry
                        entry_id = request.form.get('entry_id', type=int)

                        if not entry_id:
                            flash('Entry ID is required for deletion.', 'error')
                            return redirect(url_for('contract_hours_edit', contract_id=contract_id))

                        result = time_tracking_service.delete_time_entry(
                            entry_id=entry_id,
                            user_id=current_user.id
                        )

                        if result.get('success'):
                            flash(result.get('message'), 'success')
                        else:
                            flash(f"Error deleting hours: {result.get('error')}", 'error')

                    elif action == 'approve_hours':
                        # Approve time entries (contractor only)
                        if contract.contractor_id != current_user.id:
                            flash('Only the contractor can approve hours.', 'error')
                            return redirect(url_for('contract_hours_edit', contract_id=contract_id))

                        entry_ids_str = request.form.getlist('entry_ids')
                        entry_ids = [int(id) for id in entry_ids_str if id.isdigit()]

                        result = time_tracking_service.approve_time_entries(
                            contract_id=contract_id,
                            approver_id=current_user.id,
                            entry_ids=entry_ids if entry_ids else None
                        )

                        if result.get('success'):
                            flash(result.get('message'), 'success')
                        else:
                            flash(f"Error approving hours: {result.get('error')}", 'error')

                    return redirect(url_for('contract_hours_edit', contract_id=contract_id))

                # GET request - show edit form
                hours_data = time_tracking_service.get_contract_hours(contract_id)

                if not hours_data.get('success'):
                    flash(f"Error loading hours: {hours_data.get('error')}", 'error')
                    return redirect(url_for('contracts_review', contract_id=contract_id))

                return render_template('contracts/hours_edit.html',
                                     contract=contract,
                                     hours_data=hours_data,
                                     is_contractor=current_user.id == contract.contractor_id)
            
            except Exception as e:
                    logger.exception(f"Error editing contract hours {contract_id}: {e}")  # logs full stack trace
                    flash(f"Error loading hour editing interface: {e}", 'error')  # show actual error
                    return redirect(url_for('contracts_review', contract_id=contract_id))
            


    @app.route('/contracts/<int:contract_id>/hours/summary')
    @login_required
    def contract_hours_summary(contract_id):
            """Hour summary for contract (JSON response)"""
            from app.services.time_tracking_service import time_tracking_service
            from app.models import Contract

            try:
                # Verify user has access to this contract
                contract = Contract.query.get_or_404(contract_id)
                if current_user.id not in [contract.contractor_id, contract.worker_id]:
                    return jsonify({
                        "success": False,
                        "error": "Access denied"
                    }), 403

                # Get calculation summary
                summary = time_tracking_service.calculate_total_hours(
                    contract_id=contract_id,
                    approved_only=False  # Include all hours
                )

                if summary.get('success'):
                    # Add contract details
                    summary['contract'] = {
                        'id': contract.id,
                        'status': contract.status,
                        'agreed_rate': float(contract.agreed_rate),
                        'rate_type': contract.rate_type,
                        'worker_name': f"{contract.worker.first_name} {contract.worker.last_name}",
                        'contractor_name': f"{contract.contractor.first_name} {contract.contractor.last_name}"
                    }

                    return jsonify(summary)
                else:
                    return jsonify(summary), 400

            except Exception as e:
                logger.error(f"Error getting contract hours summary {contract_id}: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    
    @app.route('/api/time-entries', methods=['POST'])
    @login_required
    def api_create_time_entry():
            """API endpoint to create new time entries"""
            from app.services.time_tracking_service import time_tracking_service
            from datetime import date

            try:
                data = request.get_json()
                if not data:
                    return jsonify({
                        "success": False,
                        "error": "JSON data required"
                    }), 400

                # Extract required fields
                contract_id = data.get('contract_id', type=int)
                hours = data.get('hours', type=float)

                # Extract optional fields
                work_date_str = data.get('work_date')
                description = data.get('description', '')
                location = data.get('location', '')

                # Validate required fields
                if not contract_id or not hours:
                    return jsonify({
                        "success": False,
                        "error": "contract_id and hours are required"
                    }), 400

                # Parse work date
                work_date = None
                if work_date_str:
                    try:
                        work_date = date.fromisoformat(work_date_str)
                    except ValueError:
                        return jsonify({
                            "success": False,
                            "error": "Invalid work_date format. Use YYYY-MM-DD"
                        }), 400

                # Verify contract access
                from app.models import Contract
                contract = Contract.query.get(contract_id)
                if not contract:
                    return jsonify({
                        "success": False,
                        "error": "Contract not found"
                    }), 404

                if current_user.id not in [contract.contractor_id, contract.worker_id]:
                    return jsonify({
                        "success": False,
                        "error": "Access denied"
                    }), 403

                # Create time entry
                result = time_tracking_service.create_time_entry(
                    contract_id=contract_id,
                    worker_id=contract.worker_id,
                    hours=hours,
                    work_date=work_date,
                    description=description,
                    location=location
                )

                if result.get('success'):
                    return jsonify(result), 201
                else:
                    return jsonify(result), 400

            except Exception as e:
                logger.error(f"Error creating time entry via API: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    @app.route('/api/time-entries/<int:entry_id>', methods=['PUT'])
    @login_required
    def api_edit_time_entry(entry_id):
            """API endpoint to edit existing time entries"""
            from app.services.time_tracking_service import time_tracking_service
            from datetime import date

            try:
                data = request.get_json()
                if not data:
                    return jsonify({
                        "success": False,
                        "error": "JSON data required"
                    }), 400

                # Extract optional update fields
                hours = data.get('hours', type=float)
                description = data.get('description')
                location = data.get('location')
                work_date_str = data.get('work_date')

                # Parse work date if provided
                work_date = None
                if work_date_str:
                    try:
                        work_date = date.fromisoformat(work_date_str)
                    except ValueError:
                        return jsonify({
                            "success": False,
                            "error": "Invalid work_date format. Use YYYY-MM-DD"
                        }), 400

                # Edit time entry
                result = time_tracking_service.edit_time_entry(
                    entry_id=entry_id,
                    hours=hours,
                    description=description,
                    location=location,
                    work_date=work_date,
                    user_id=current_user.id
                )

                if result.get('success'):
                    return jsonify(result)
                else:
                    return jsonify(result), 400

            except Exception as e:
                logger.error(f"Error editing time entry {entry_id} via API: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    @app.route('/api/time-entries/<int:entry_id>', methods=['DELETE'])
    @login_required
    def api_delete_time_entry(entry_id):
            """API endpoint to delete time entries"""
            from app.services.time_tracking_service import time_tracking_service

            try:
                result = time_tracking_service.delete_time_entry(
                    entry_id=entry_id,
                    user_id=current_user.id
                )

                if result.get('success'):
                    return jsonify(result)
                else:
                    return jsonify(result), 400

            except Exception as e:
                logger.error(f"Error deleting time entry {entry_id} via API: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    @app.route('/api/contracts/<int:contract_id>/time-entries')
    @login_required
    def api_get_contract_time_entries(contract_id):
            """API endpoint to get all time entries for a contract"""
            from app.services.time_tracking_service import time_tracking_service

            try:
                # Get contract hours with full details
                result = time_tracking_service.get_contract_hours(contract_id)

                if result.get('success'):
                    return jsonify(result)
                else:
                    return jsonify(result), 400

            except Exception as e:
                logger.error(f"Error getting contract time entries {contract_id} via API: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    @app.route('/api/contracts/<int:contract_id>/approve-hours', methods=['POST'])
    @login_required
    def api_approve_contract_hours(contract_id):
            """API endpoint to approve time entries for a contract"""
            from app.services.time_tracking_service import time_tracking_service

            try:
                data = request.get_json() or {}
                entry_ids = data.get('entry_ids')  # Optional - if None, approves all pending

                result = time_tracking_service.approve_time_entries(
                    contract_id=contract_id,
                    approver_id=current_user.id,
                    entry_ids=entry_ids
                )

                if result.get('success'):
                    return jsonify(result)
                else:
                    return jsonify(result), 400

            except Exception as e:
                logger.error(f"Error approving hours {contract_id} via API: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    @app.route('/api/time-tracking/clock-in', methods=['POST'])
    @login_required
    def api_clock_in():
            """API endpoint for worker clock-in"""
            from app.services.time_tracking_service import time_tracking_service

            try:
                data = request.get_json()
                if not data:
                    return jsonify({
                        "success": False,
                        "error": "JSON data required"
                    }), 400

                contract_id = data.get('contract_id', type=int)
                location = data.get('location', '')
                description = data.get('description', '')

                if not contract_id:
                    return jsonify({
                        "success": False,
                        "error": "contract_id is required"
                    }), 400

                result = time_tracking_service.clock_in(
                    worker_id=current_user.id,
                    contract_id=contract_id,
                    location=location,
                    description=description
                )

                if result.get('success'):
                    return jsonify(result)
                else:
                    return jsonify(result), 400

            except Exception as e:
                logger.error(f"Error clocking in via API: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    @app.route('/api/time-tracking/clock-out', methods=['POST'])
    @login_required
    def api_clock_out():
            """API endpoint for worker clock-out"""
            from app.services.time_tracking_service import time_tracking_service

            try:
                data = request.get_json() or {}
                entry_id = data.get('entry_id', type=int)
                description = data.get('description', '')

                result = time_tracking_service.clock_out(
                    worker_id=current_user.id,
                    entry_id=entry_id,
                    description=description
                )

                if result.get('success'):
                    return jsonify(result)
                else:
                    return jsonify(result), 400

            except Exception as e:
                logger.error(f"Error clocking out via API: {e}")
                return jsonify({
                    "success": False,
                    "error": "Internal server error"
                }), 500

    @app.route('/api/time-tracking/active-clock-in')
    @login_required
    def api_get_active_clock_in():
            """API endpoint to get worker's active clock-in"""
            from app.services.time_tracking_service import time_tracking_service

            try:
                result = time_tracking_service.get_active_clock_in(current_user.id)
                return jsonify(result)

            except Exception as e:
                logger.error(f"Error getting active clock-in via API: {e}")
                return jsonify({
                    "active": False,
                    "error": "Internal server error"
                }), 500

        # ==================== EXPORT FUNCTIONALITY ====================

    @app.route('/contracts/<int:contract_id>/hours/export')
    @login_required
    def export_contract_hours(contract_id):
            """Export contract hours as CSV or PDF"""
            from app.services.export_service import export_service
            from app.models import Contract
            from flask import make_response
            from datetime import date, datetime

            try:
                # Verify user has access to this contract
                contract = Contract.query.get_or_404(contract_id)
                if current_user.id not in [contract.contractor_id, contract.worker_id]:
                    flash('You do not have access to this contract.', 'error')
                    return redirect(url_for('dashboard'))

                # Get export parameters
                export_format = request.args.get('format', 'csv').lower()
                start_date_str = request.args.get('start_date')
                end_date_str = request.args.get('end_date')
                approved_only = request.args.get('approved_only', 'false').lower() == 'true'

                # Parse dates if provided
                start_date = None
                end_date = None

                if start_date_str:
                    try:
                        start_date = date.fromisoformat(start_date_str)
                    except ValueError:
                        flash('Invalid start date format.', 'error')
                        return redirect(url_for('contract_hours_view', contract_id=contract_id))

                if end_date_str:
                    try:
                        end_date = date.fromisoformat(end_date_str)
                    except ValueError:
                        flash('Invalid end date format.', 'error')
                        return redirect(url_for('contract_hours_view', contract_id=contract_id))

                # Validate date range
                if start_date and end_date and start_date > end_date:
                    flash('Start date cannot be after end date.', 'error')
                    return redirect(url_for('contract_hours_view', contract_id=contract_id))

                # Export based on format
                if export_format == 'pdf':
                    export_result = export_service.export_contract_hours_pdf(
                        contract_id=contract_id,
                        start_date=start_date,
                        end_date=end_date,
                        approved_only=approved_only
                    )

                    if export_result.get('success'):
                        response = make_response(export_result['pdf_data'])
                        response.headers['Content-Type'] = 'application/pdf'
                        response.headers['Content-Disposition'] = f'attachment; filename="{export_result["filename"]}"'
                        return response
                    else:
                        flash(f"Export failed: {export_result.get('error')}", 'error')
                        return redirect(url_for('contract_hours_view', contract_id=contract_id))

                else:  # Default to CSV
                    export_result = export_service.export_contract_hours_csv(
                        contract_id=contract_id,
                        start_date=start_date,
                        end_date=end_date,
                        approved_only=approved_only
                    )

                    if export_result.get('success'):
                        response = make_response(export_result['csv_data'])
                        response.headers['Content-Type'] = 'text/csv'
                        response.headers['Content-Disposition'] = f'attachment; filename="{export_result["filename"]}"'
                        return response
                    else:
                        flash(f"Export failed: {export_result.get('error')}", 'error')
                        return redirect(url_for('contract_hours_view', contract_id=contract_id))

            except Exception as e:
                logger.error(f"Error exporting contract hours {contract_id}: {e}")
                flash('Error generating export.', 'error')
                return redirect(url_for('contract_hours_view', contract_id=contract_id))

    @app.route('/contracts/<int:contract_id>/payroll/export')
    @login_required
    def export_payroll_summary(contract_id):
            """Export payroll summary for contractor"""
            from app.services.export_service import export_service
            from app.models import Contract
            from flask import make_response
            from datetime import date

            try:
                # Verify user is contractor for this contract
                contract = Contract.query.get_or_404(contract_id)
                if current_user.id != contract.contractor_id:
                    flash('Only contractors can export payroll data.', 'error')
                    return redirect(url_for('dashboard'))

                # Get required date range parameters
                start_date_str = request.args.get('start_date')
                end_date_str = request.args.get('end_date')

                if not start_date_str or not end_date_str:
                    flash('Start date and end date are required for payroll export.', 'error')
                    return redirect(url_for('contract_hours_view', contract_id=contract_id))

                try:
                    start_date = date.fromisoformat(start_date_str)
                    end_date = date.fromisoformat(end_date_str)
                except ValueError:
                    flash('Invalid date format.', 'error')
                    return redirect(url_for('contract_hours_view', contract_id=contract_id))

                # Export payroll summary
                export_result = export_service.export_payroll_summary_csv(
                    contractor_id=current_user.id,
                    start_date=start_date,
                    end_date=end_date,
                    approved_only=True  # Payroll should only include approved hours
                )

                if export_result.get('success'):
                    response = make_response(export_result['csv_data'])
                    response.headers['Content-Type'] = 'text/csv'
                    response.headers['Content-Disposition'] = f'attachment; filename="{export_result["filename"]}"'
                    return response
                else:
                    flash(f"Payroll export failed: {export_result.get('error')}", 'error')
                    return redirect(url_for('contract_hours_view', contract_id=contract_id))

            except Exception as e:
                logger.error(f"Error exporting payroll summary: {e}")
                flash('Error generating payroll export.', 'error')
                return redirect(url_for('contract_hours_view', contract_id=contract_id))



    # ==================== OAUTH DRIVE INTEGRATION ROUTES ====================

    @app.route('/oauth2callback')
    @login_required
    def oauth2callback():
        """Handle Google Drive OAuth callback"""
        try:
            from app.services.drive_oauth_service import DriveOAuthService

            authorization_code = request.args.get('code')
            if not authorization_code:
                flash('OAuth authorization failed - no authorization code received.', 'error')
                return redirect(url_for('dashboard'))

            drive_service = DriveOAuthService()
            success = drive_service.handle_oauth_callback(authorization_code)

            if success:
                flash('Google Drive successfully connected! Contract PDFs will now be automatically uploaded.', 'success')
            else:
                flash('Failed to connect Google Drive. Please try again.', 'error')

            return redirect(url_for('dashboard'))

        except Exception as e:
            logger.error(f"OAuth callback error: {str(e)}")
            flash('Error connecting to Google Drive. Please try again later.', 'error')
            return redirect(url_for('dashboard'))

    @app.route('/drive/connect')
    @login_required
    def drive_connect():
        """Initiate Google Drive OAuth connection"""
        try:
            from app.services.drive_oauth_service import DriveOAuthService

            drive_service = DriveOAuthService()
            auth_url = drive_service.get_authorization_url()

            return redirect(auth_url)

        except Exception as e:
            logger.error(f"Drive connect error: {str(e)}")
            flash('Error initiating Google Drive connection. Please try again later.', 'error')
            return redirect(url_for('dashboard'))

    def register_edge_error_handlers(app):
        """Register Edge-specific error handlers"""

        @app.errorhandler(500)
        def handle_edge_500_error(error):
            """Enhanced 500 error handler for Edge browser issues"""
            from flask import request
            import traceback

            user_agent = request.headers.get('User-Agent', '')
            is_edge = 'Edg/' in user_agent

            if is_edge:
                print(f"[EDGE] 500 error detected in Edge browser")
                print(f"[EDGE] URL: {request.url}")
                print(f"[EDGE] Method: {request.method}")
                print(f"[EDGE] Headers: {dict(request.headers)}")
                print(f"[EDGE] Error: {str(error)}")

                # Return Edge-friendly error page
                edge_error_html = """
                <!DOCTYPE html>
                <html><head>
                    <title>RateRight - Loading...</title>
                    <meta http-equiv="refresh" content="2;url=/">
                    <meta charset="UTF-8">
                    <meta name="viewport" content="width=device-width, initial-scale=1.0">
                    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
                </head><body>
                    <div style="text-align: center; padding: 50px; font-family: Arial, sans-serif;">
                        <h2>RateRight - Microsoft Edge Compatibility</h2>
                        <p>Optimizing experience for Edge browser...</p>
                        <p>Redirecting automatically...</p>
                        <p><a href="/">Click here if not redirected</a></p>
                    </div>
                    <script>
                        // Force redirect after brief delay for Edge
                        setTimeout(function() {
                            window.location.href = '/';
                        }, 1000);
                    </script>
                </body></html>
                """
                return edge_error_html, 500

            # Standard error handling for other browsers
            return f"<h1>500 - Internal Server Error</h1><p>RateRight encountered an error: {str(error)}</p>", 500

    @app.route('/scheduling/calendar')
    def scheduling_calendar():
        """Render the scheduling calendar page."""
        return render_template('scheduling/calendar.html')

    @app.route('/time-tracking')
    @login_required
    def time_tracking_summary():
        """Display aggregate time tracking across all contracts"""
        from app.models import Contract
        from app.services.time_tracking_service import time_tracking_service
        
        # Get all contracts for the current user
        contracts = Contract.query.filter(
            (Contract.worker_id == current_user.id) | (Contract.contractor_id == current_user.id)
        ).order_by(Contract.created_at.desc()).all()

        # Aggregate hours data across all contracts
        contracts_with_hours = []
        total_hours_all = 0
        total_approved_all = 0
        total_pending_all = 0
        total_contracts = 0
        
        for contract in contracts:
            hours_data = time_tracking_service.get_contract_hours(contract.id)
            if hours_data.get('success'):
                contracts_with_hours.append({
                    'contract': contract,
                    'hours_data': hours_data
                })
                total_hours_all += hours_data['summary']['total_hours']
                total_approved_all += hours_data['summary']['approved_hours']
                total_pending_all += hours_data['summary']['pending_entries']
                total_contracts += 1
        
        # Create aggregate summary
        aggregate_summary = {
            'total_hours': round(total_hours_all, 2),
            'approved_hours': round(total_approved_all, 2),
            'pending_entries': total_pending_all,
            'total_contracts': total_contracts,
            'active_contracts': len([c for c in contracts if c.status == 'active'])
        }
        
        return render_template(
            'time_tracking/summary.html',
            contracts_with_hours=contracts_with_hours,
            aggregate_summary=aggregate_summary,
            current_user=current_user
        )
