from flask import request, jsonify
from flask_login import login_required, current_user
from datetime import datetime

from . import marketplace_bp
from ...extensions import db
from ...models import Job, Application, User, Category
from ...models.enums import JobStatus, ApplicationStatus
from ...services.notification_service import notification_service
from ...models.notification import NotificationType


@marketplace_bp.route('/jobs', methods=['GET'])
def get_jobs():
    """Get all available jobs with filtering"""
    try:
        # Get query parameters
        category_id = request.args.get('category_id', type=int)
        location = request.args.get('location')
        min_budget = request.args.get('min_budget', type=float)
        max_budget = request.args.get('max_budget', type=float)
        page = request.args.get('page', 1, type=int)
        per_page = min(request.args.get('per_page', 10, type=int), 100)

        # Build query
        query = Job.query.filter_by(status=JobStatus.OPEN)

        if category_id:
            query = query.filter_by(category_id=category_id)

        if location:
            query = query.filter(Job.location.ilike(f'%{location}%'))

        if min_budget:
            query = query.filter(Job.budget_min >= min_budget)

        if max_budget:
            query = query.filter(Job.budget_max <= max_budget)

        # Order by date posted (newest first)
        query = query.order_by(Job.date_posted.desc())

        # Paginate
        jobs = query.paginate(page=page, per_page=per_page, error_out=False)

        return jsonify({
            'jobs': [{
                'id': job.id,
                'title': job.title,
                'description': job.description,
                'location': job.location,
                'budget_min': float(job.budget_min) if job.budget_min else None,
                'budget_max': float(job.budget_max) if job.budget_max else None,
                'hourly_rate': float(job.hourly_rate) if job.hourly_rate else None,
                'duration': job.duration,
                'workers_needed': job.workers_needed,
                'start_datetime': job.start_datetime.isoformat() if job.start_datetime else None,
                'own_tools_required': job.own_tools_required,
                'own_transport_required': job.own_transport_required,
                'payment_terms': job.payment_terms,
                'category': job.category.name,
                'contractor_name': f"{job.contractor.first_name} {job.contractor.last_name}",
                'contractor_id': job.contractor_id,
                'whs_requirements': job.whs_requirements,
                'insurance_required': job.insurance_required,
                'white_card_required': job.white_card_required,
                'date_posted': job.date_posted.isoformat(),
                'deadline': job.deadline.isoformat() if job.deadline else None,
                'applications_count': job.applications_count,
                'user_has_applied': (
                    Application.query.filter_by(
                        job_id=job.id,
                        worker_id=current_user.id
                    ).first() is not None
                ) if current_user.is_authenticated and current_user.role == 'worker' else False
            } for job in jobs.items],
            'pagination': {
                'page': jobs.page,
                'per_page': jobs.per_page,
                'total': jobs.total,
                'pages': jobs.pages,
                'has_next': jobs.has_next,
                'has_prev': jobs.has_prev
            }
        }), 200

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/jobs/<int:job_id>', methods=['GET'])
def get_job(job_id):
    """Get single job details"""
    try:
        job = Job.query.get_or_404(job_id)

        return jsonify({
            'job': {
                'id': job.id,
                'title': job.title,
                'description': job.description,
                'location': job.location,
                'budget_min': float(job.budget_min) if job.budget_min else None,
                'budget_max': float(job.budget_max) if job.budget_max else None,
                'category': {
                    'id': job.category.id,
                    'name': job.category.name,
                    'whs_risk_level': job.category.whs_risk_level
                },
                'contractor': {
                    'id': job.contractor.id,
                    'name': f"{job.contractor.first_name} {job.contractor.last_name}",
                    'business_name': job.contractor.business_name,
                    'average_rating': float(job.contractor.average_rating) if job.contractor.average_rating else 0.0,
                    'jobs_completed': job.contractor.jobs_completed
                },
                'whs_requirements': job.whs_requirements,
                'insurance_required': job.insurance_required,
                'white_card_required': job.white_card_required,
                'date_posted': job.date_posted.isoformat(),
                'deadline': job.deadline.isoformat() if job.deadline else None,
                'applications_count': job.applications_count,
                'status': job.status
            }
        }), 200

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/jobs/<int:job_id>/apply', methods=['POST'])
@login_required
def apply_to_job(job_id):
    """Apply to a job (workers only)"""
    try:
        user = current_user
        
        if not user.is_authenticated:
            return jsonify({'error': 'Please login to apply'}), 401

        if user.role != 'worker':
            return jsonify({'error': 'Only workers can apply to jobs'}), 403

        job = Job.query.get_or_404(job_id)

        if job.status != JobStatus.OPEN:
            return jsonify({'error': 'Job is not open for applications'}), 400

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

        if existing_application:
            return jsonify({'error': 'You have already applied to this job'}), 400

        data = request.get_json()

        # Create application
        application = Application(
            job_id=job_id,
            worker_id=user.id,
            proposed_rate=data.get('proposed_rate'),
            cover_letter=data.get('cover_letter'),
            abn_verified=True,  # We assume ABN is verified during registration
            insurance_verified=user.public_liability_insurance
        )

        db.session.add(application)

        # Update job applications count
        job.applications_count += 1

        db.session.commit()

        # NOTIFICATION TRIGGER: Notify contractor about new application (non-blocking)
        # Schedule notification to be sent after response is returned
        from threading import Thread
        def send_notification_async():
            try:
                notification_service.send_notification(
                    user_id=job.contractor_id,
                    notification_type=NotificationType.JOB_APPLICATION_UPDATE,
                    title=f"New Application for '{job.title}'",
                    content=f"{user.first_name} {user.last_name} has applied to your job '{job.title}' in {job.location}. Proposed rate: ${application.proposed_rate}/hour.",
                    priority=3,  # Important but not urgent
                    category="job_alerts",
                    action_url=f"/applications/received?job_id={job.id}"
                )
            except Exception as e:
                # Log error but don't fail the application process
                print(f"Failed to send application notification: {e}")
        
        # Send notification in background thread to avoid blocking response
        Thread(target=send_notification_async).start()

        # Flash success message for dashboard
        from flask import flash
        flash('Application submitted successfully! The contractor has been notified.', 'success')

        return jsonify({
            'message': 'Application submitted successfully',
            'application_id': application.id
        }), 201

    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/categories', methods=['GET'])
def get_categories():
    """Get all active job categories"""
    try:
        categories = Category.query.filter_by(is_active=True).order_by(Category.sort_order, Category.name).all()

        return jsonify({
            'categories': [{
                'id': category.id,
                'name': category.name,
                'description': category.description,
                'whs_risk_level': category.whs_risk_level,
                'insurance_minimum': category.get_insurance_minimum(),
                'license_required': category.license_required,
                'white_card_required': category.white_card_required
            } for category in categories]
        }), 200

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/my-applications', methods=['GET'])
@login_required
def get_my_applications():
    """Get current user's job applications"""
    try:
        user = current_user

        if not user or user.role != 'worker':
            return jsonify({'error': 'Only workers can view applications'}), 403

        applications = Application.query.filter_by(worker_id=user.id).order_by(Application.date_applied.desc()).all()

        return jsonify({
            'applications': [{
                'id': app.id,
                'job': {
                    'id': app.job.id,
                    'title': app.job.title,
                    'location': app.job.location,
                    'contractor_name': f"{app.job.contractor.first_name} {app.job.contractor.last_name}"
                },
                'status': app.status,
                'proposed_rate': float(app.proposed_rate) if app.proposed_rate else None,
                'date_applied': app.date_applied.isoformat(),
                'abn_verified': app.abn_verified,
                'insurance_verified': app.insurance_verified
            } for app in applications]
        }), 200

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/jobs', methods=['POST'])
@login_required
def create_job():
    """Create a new job (contractors only)"""
    try:
        user = current_user

        if not user:
            return jsonify({'error': 'User not found'}), 404

        if user.role != 'contractor':
            return jsonify({'error': 'Only contractors can post jobs'}), 403

        # Check contractor compliance
        compliance_valid, compliance_issues = user.is_compliance_valid()
        if not compliance_valid:
            return jsonify({
                'error': 'Contractor compliance required to post jobs',
                'issues': compliance_issues
            }), 400

        data = request.get_json()

        # Validate required fields
        required_fields = ['title', 'description', 'category_id', 'location']
        for field in required_fields:
            if not data.get(field):
                return jsonify({'error': f'{field} is required'}), 400

        # Validate category exists
        category = Category.query.get(data['category_id'])
        if not category or not category.is_active:
            return jsonify({'error': 'Invalid or inactive category'}), 400

        # Create job
        job = Job(
            title=data['title'],
            description=data['description'],
            contractor_id=user.id,  # Fixed: was user_id
            category_id=data['category_id'],
            location=data['location'],
            budget_min=data.get('budget_min'),
            budget_max=data.get('budget_max'),
            duration=data.get('duration'),  # FIX: Add missing duration field
            workers_needed=data.get('workers_needed', 1),  # FIX: Add missing workers_needed field
            own_tools_required=data.get('own_tools_required', False),  # FIX: Add missing own_tools_required field
            own_transport_required=data.get('own_transport_required', False),  # FIX: Add missing own_transport_required field
            whs_requirements=data.get('whs_requirements') or f"Category: {category.name}. Risk Level: {category.whs_risk_level}. {category.insurance_requirements or ''}",
            insurance_required=data.get('insurance_required', True),
            white_card_required=data.get('white_card_required', category.white_card_required),
            deadline=datetime.fromisoformat(data['deadline']) if data.get('deadline') else None
        )

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

        # Award points for posting job
        from ...utils.gamification import award_points
        award_points(user.id, 'job_posted', 50)

        # NOTIFICATION TRIGGER: Notify matching workers about new job
        try:
            # Find workers in the same location and category
            matching_workers = User.query.filter(
                User.role == 'worker',
                User.location.ilike(f'%{job.location}%'),
                User.primary_trade == category.name
            ).limit(50).all()  # Limit to prevent spam
            
            for worker in matching_workers:
                notification_service.send_notification(
                    user_id=worker.id,
                    notification_type=NotificationType.JOB_MATCH,
                    title=f"New Job Match: {job.title}",
                    content=f"A new {category.name} job in {job.location} matches your profile. Budget: ${job.budget_min}-${job.budget_max}/hour. Apply now!",
                    priority=4,  # Normal priority for job matches
                    category="job_alerts",
                    action_url=f"/jobs/{job.id}"
                )
        except Exception as e:
            # Log error but don't fail the job posting
            print(f"Failed to send job match notifications: {e}")

        return jsonify({
            'message': 'Job posted successfully',
            'job_id': job.id,
            'job': {
                'id': job.id,
                'title': job.title,
                'location': job.location,
                'status': job.status,
                'date_posted': job.date_posted.isoformat()
            }
        }), 201

    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/jobs/<int:job_id>', methods=['PUT'])
@login_required
def update_job(job_id):
    """Update job details (job owner only)"""
    try:
        user = current_user
        job = Job.query.get_or_404(job_id)

        # Check ownership
        if job.contractor_id != user.id:
            return jsonify({'error': 'You can only update your own jobs'}), 403

        # Don't allow updates if job has applications
        if job.applications_count > 0:
            return jsonify({'error': 'Cannot update job with existing applications'}), 400

        data = request.get_json()

        # Update allowed fields
        updatable_fields = ['title', 'description', 'location', 'budget_min', 
                           'budget_max', 'whs_requirements', 'deadline']

        for field in updatable_fields:
            if field in data:
                if field == 'deadline' and data[field]:
                    setattr(job, field, datetime.fromisoformat(data[field]))
                else:
                    setattr(job, field, data[field])

        db.session.commit()

        return jsonify({
            'message': 'Job updated successfully',
            'job': {
                'id': job.id,
                'title': job.title,
                'description': job.description,
                'location': job.location,
                'budget_min': float(job.budget_min) if job.budget_min else None,
                'budget_max': float(job.budget_max) if job.budget_max else None,
                'status': job.status
            }
        }), 200

    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/my-jobs', methods=['GET'])
@login_required
def get_my_jobs():
    """Get contractor's posted jobs"""
    try:
        user = current_user

        if not user or user.role != 'contractor':
            return jsonify({'error': 'Only contractors can view posted jobs'}), 403

        status = request.args.get('status', 'all')
        page = request.args.get('page', 1, type=int)
        per_page = min(request.args.get('per_page', 10, type=int), 100)

        # Build query
        query = Job.query.filter_by(contractor_id=user.id)

        if status != 'all':
            query = query.filter_by(status=status)

        query = query.order_by(Job.date_posted.desc())

        # Paginate
        jobs = query.paginate(page=page, per_page=per_page, error_out=False)

        return jsonify({
            'jobs': [{
                'id': job.id,
                'title': job.title,
                'location': job.location,
                'status': job.status,
                'budget_min': float(job.budget_min) if job.budget_min else None,
                'budget_max': float(job.budget_max) if job.budget_max else None,
                'applications_count': job.applications_count,
                'date_posted': job.date_posted.isoformat(),
                'deadline': job.deadline.isoformat() if job.deadline else None,
                'category': job.category.name
            } for job in jobs.items],
            'pagination': {
                'page': jobs.page,
                'per_page': jobs.per_page,
                'total': jobs.total,
                'pages': jobs.pages
            }
        }), 200

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/jobs/<int:job_id>/applications', methods=['GET'])
@login_required
def get_job_applications(job_id):
    """Get applications for a specific job (job owner only)"""
    try:
        user = current_user
        job = Job.query.get_or_404(job_id)

        # Check ownership
        if job.contractor_id != user.id:
            return jsonify({'error': 'You can only view applications for your own jobs'}), 403

        applications = Application.query.filter_by(job_id=job_id).order_by(Application.date_applied.desc()).all()

        return jsonify({
            'job': {
                'id': job.id,
                'title': job.title,
                'applications_count': job.applications_count
            },
            'applications': [{
                'id': app.id,
                'worker': {
                    'id': app.worker.id,
                    'name': f"{app.worker.first_name} {app.worker.last_name}",
                    'primary_trade': app.worker.primary_trade,
                    'average_rating': float(app.worker.average_rating) if app.worker.average_rating else 0.0,
                    'jobs_completed': app.worker.jobs_completed,
                    'location': app.worker.location
                },
                'status': app.status,
                'proposed_rate': float(app.proposed_rate) if app.proposed_rate else None,
                'cover_letter': app.cover_letter,
                'date_applied': app.date_applied.isoformat(),
                'abn_verified': app.abn_verified,
                'insurance_verified': app.insurance_verified,
                'compliance_valid': app.worker.is_compliance_valid()[0]
            } for app in applications]
        }), 200

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/applications/<int:application_id>', methods=['PUT'])
@login_required
def update_application_status(application_id):
    """Accept or reject job application (job owner only)"""
    try:
        user = current_user
        application = Application.query.get_or_404(application_id)

        # Check if user owns the job
        if application.job.contractor_id != user.id:
            return jsonify({'error': 'You can only manage applications for your own jobs'}), 403

        data = request.get_json()
        new_status = data.get('status')

        if new_status not in [ApplicationStatus.ACCEPTED, ApplicationStatus.REJECTED]:
            return jsonify({'error': 'Status must be "accepted" or "rejected"'}), 400

        if application.status != ApplicationStatus.PENDING:
            return jsonify({'error': 'Can only update pending applications'}), 400

        application.status = new_status

        # If accepted, close the job and reject other applications
        if new_status == ApplicationStatus.ACCEPTED:
            application.job.status = JobStatus.ASSIGNED

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

            for other_app in other_applications:
                other_app.status = ApplicationStatus.REJECTED

            # Award points to both contractor and worker
            from ...utils.gamification import award_points
            award_points(application.job.contractor_id, 'application_accepted', 25)
            award_points(application.worker_id, 'application_accepted', 75)

        db.session.commit()

        # NOTIFICATION TRIGGERS: Notify worker about application status
        try:
            if new_status == ApplicationStatus.ACCEPTED:
                # Notify worker about acceptance - this is CONTRACT_AWARDED
                notification_service.send_notification(
                    user_id=application.worker_id,
                    notification_type=NotificationType.CONTRACT_AWARDED,
                    title=f"Congratulations! Job Awarded: '{application.job.title}'",
                    content=f"Your application for '{application.job.title}' in {application.job.location} has been accepted! The contractor will contact you soon with next steps.",
                    priority=2,  # High priority - good news!
                    category="job_alerts",
                    action_url=f"/contracts/{application.job.id}"
                )
            else:  # REJECTED
                # Notify worker about rejection
                notification_service.send_notification(
                    user_id=application.worker_id,
                    notification_type=NotificationType.JOB_APPLICATION_UPDATE,
                    title=f"Application Update: '{application.job.title}'",
                    content=f"Your application for '{application.job.title}' was not selected this time. Keep applying - there are always new opportunities!",
                    priority=5,  # Normal priority
                    category="job_alerts",
                    action_url="/jobs"
                )
        except Exception as e:
            # Log error but don't fail the process
            print(f"Failed to send application status notification: {e}")

        return jsonify({
            'message': f'Application {new_status} successfully',
            'application': {
                'id': application.id,
                'status': application.status,
                'worker_name': f"{application.worker.first_name} {application.worker.last_name}",
                'job_title': application.job.title
            }
        }), 200

    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500


@marketplace_bp.route('/jobs/<int:job_id>/close', methods=['PUT'])
@login_required
def close_job(job_id):
    """Close a job posting (job owner only)"""
    try:
        user = current_user
        job = Job.query.get_or_404(job_id)

        # Check ownership
        if job.contractor_id != user.id:
            return jsonify({'error': 'You can only close your own jobs'}), 403

        if job.status not in [JobStatus.OPEN, JobStatus.ASSIGNED]:
            return jsonify({'error': 'Job is already closed'}), 400

        job.status = JobStatus.CANCELLED

        # Reject all pending applications
        pending_applications = Application.query.filter_by(
            job_id=job_id,
            status=ApplicationStatus.PENDING
        ).all()

        for app in pending_applications:
            app.status = ApplicationStatus.REJECTED

        db.session.commit()

        return jsonify({
            'message': 'Job closed successfully',
            'job': {
                'id': job.id,
                'title': job.title,
                'status': job.status
            }
        }), 200

    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500
