
from flask import request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from datetime import datetime, date, timedelta
import logging
import uuid

from . import legal_bp
from ...models import Contract, Payment, Invoice, Job, User
from ...extensions import db, limiter, csrf
from ...utils.compliance import (
    calculate_gst, generate_payment_reference, 
    calculate_withholding_tax, validate_contract_terms, calculate_total_with_gst
)

# Security: Maximum payment amount to prevent abuse
MAX_PAYMENT_AMOUNT_AUD = 1000000  # $1M AUD

logger = logging.getLogger(__name__)


@legal_bp.route('/contracts', methods=['POST'])
@jwt_required()
def create_contract():
    """Create new contract between contractor and worker"""
    try:
        current_user_id = get_jwt_identity()
        data = request.get_json()
        
        # Validation
        required_fields = ['job_id', 'worker_id', 'agreed_rate', 'start_date', 'end_date', 'scope_of_work']
        for field in required_fields:
            if not data.get(field):
                return jsonify({"error": f"{field} is required"}), 400
        
        # Verify job ownership
        job = Job.query.get(data['job_id'])
        if not job or job.contractor_id != current_user_id:
            return jsonify({"error": "Job not found or unauthorized"}), 404
        
        # Verify worker exists
        worker = User.query.get(data['worker_id'])
        if not worker or worker.role != 'worker':
            return jsonify({"error": "Invalid worker"}), 400
        
        # Parse dates
        start_date = datetime.strptime(data['start_date'], '%Y-%m-%d').date()
        end_date = datetime.strptime(data['end_date'], '%Y-%m-%d').date()
        
        # Validate contract terms
        is_valid, validation_errors = validate_contract_terms(
            start_date, end_date, float(data['agreed_rate'])
        )
        if not is_valid:
            return jsonify({"error": "Contract validation failed", "details": validation_errors}), 400
        
        # Create contract
        contract = Contract(
            job_id=data['job_id'],
            contractor_id=current_user_id,
            worker_id=data['worker_id'],
            agreed_rate=data['agreed_rate'],
            rate_type=data.get('rate_type', 'total'),
            start_date=start_date,
            end_date=end_date,
            scope_of_work=data['scope_of_work'],
            payment_terms=data.get('payment_terms', 'completion'),
            payment_schedule=data.get('payment_schedule')
        )
        
        db.session.add(contract)
        db.session.commit()
        
        return jsonify({
            "message": "Contract created successfully",
            "contract": {
                "id": contract.id,
                "job_id": contract.job_id,
                "agreed_rate": float(contract.agreed_rate),
                "start_date": contract.start_date.isoformat(),
                "end_date": contract.end_date.isoformat(),
                "status": contract.status,
                "total_value": contract.calculate_total_value()
            }
        }), 201
        
    except ValueError as e:
        return jsonify({"error": f"Invalid date format: {str(e)}"}), 400
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": f"Contract creation failed: {str(e)}"}), 500


@legal_bp.route('/contracts/<int:contract_id>/sign', methods=['PUT'])
@jwt_required()
def sign_contract(contract_id):
    """Sign contract (contractor or worker)"""
    try:
        current_user_id = get_jwt_identity()
        contract = Contract.query.get_or_404(contract_id)
        
        # Check authorization
        if current_user_id not in [contract.contractor_id, contract.worker_id]:
            return jsonify({"error": "Unauthorized to sign this contract"}), 403
        
        # Sign contract
        if contract.contractor_id == current_user_id:
            contract.contractor_signed = True
            contract.contractor_signed_date = datetime.utcnow()
        elif contract.worker_id == current_user_id:
            contract.worker_signed = True
            contract.worker_signed_date = datetime.utcnow()
        
        # Update status if both signed
        if contract.is_fully_signed():
            contract.status = 'signed'
        
        db.session.commit()
        
        return jsonify({
            "message": "Contract signed successfully",
            "contract_status": contract.status,
            "fully_signed": contract.is_fully_signed()
        })
        
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": f"Contract signing failed: {str(e)}"}), 500


@legal_bp.route('/payments', methods=['POST'])
@limiter.limit("10 per hour")
def process_stripe_payment():
    """Process $50 flat hiring fee payment via Stripe"""
    from flask_login import current_user

    if not current_user.is_authenticated:
        logger.warning(f"Unauthenticated payment attempt from IP: {request.remote_addr}")
        return jsonify({"error": "Authentication required"}), 401

    idempotency_key = str(uuid.uuid4())

    try:
        from ...services.stripe_service import stripe_service
        import stripe

        current_user_id = current_user.id
        logger.info(f"Hiring fee payment initiated by user {current_user_id}")

        data = request.get_json()

        required_fields = ['contract_id', 'payment_method_id']
        for field in required_fields:
            if not data.get(field):
                return jsonify({"error": f"{field} is required"}), 400

        contract_id = data['contract_id']

        try:
            contract = Contract.query.filter_by(id=contract_id).with_for_update().first()
            if not contract or contract.contractor_id != current_user_id:
                return jsonify({"error": "Contract not found or unauthorized"}), 404

            if contract.status in ['cancelled', 'completed', 'disputed']:
                return jsonify({"error": f"Cannot process payment - contract status is '{contract.status}'"}), 400

            if contract.hiring_fee_paid:
                return jsonify({"error": "Hiring fee already paid for this contract"}), 400

            # Check for existing payment
            existing_payment = Payment.query.filter(
                Payment.contract_id == contract.id,
                Payment.status.in_(['pending_payment', 'held_escrow', 'paid'])
            ).with_for_update().first()

            if existing_payment:
                return jsonify({"error": "Payment already exists for this contract"}), 400

            # Create payment record for flat $50 fee
            payment = Payment(
                contract_id=contract.id,
                payment_reference=generate_payment_reference(),
                dispute_period_days=0,
                status='pending_payment'
            )
            payment.contract = contract
            payment.calculate_amounts()  # Sets flat $50

            db.session.add(payment)
            db.session.flush()

            # Create Stripe PaymentIntent for $50 (captured immediately, no escrow)
            try:
                stripe.api_key = stripe_service._ensure_stripe_key() or stripe.api_key
                stripe_service._ensure_stripe_key()

                intent = stripe.PaymentIntent.create(
                    amount=5500,  # $55 AUD in cents ($50 + $5 GST)
                    currency='aud',
                    metadata={
                        'payment_id': payment.id,
                        'contract_id': contract.id,
                        'payment_reference': payment.payment_reference,
                        'type': 'hiring_fee'
                    },
                    description='RateRight Hiring Fee',
                    idempotency_key=idempotency_key
                )
                logger.info(f"Stripe PaymentIntent created: {intent.id}")
            except Exception as intent_error:
                logger.error(f"Failed to create PaymentIntent: {intent_error}")
                db.session.rollback()
                return jsonify({"error": "Failed to create payment intent", "details": str(intent_error)}), 400

            payment.stripe_payment_intent_id = intent.id
            payment.date_initiated = datetime.utcnow()

            # Confirm payment immediately (no manual capture/escrow)
            try:
                from flask import url_for
                return_url = url_for('payment_return_handler',
                                    contract_id=contract.id,
                                    _external=True,
                                    _scheme='https')

                confirmed_intent = stripe.PaymentIntent.confirm(
                    intent.id,
                    payment_method=data['payment_method_id'],
                    return_url=return_url,
                    idempotency_key=f"{idempotency_key}-confirm"
                )
                logger.info(f"Payment confirmed, status: {confirmed_intent.status}")
            except Exception as stripe_error:
                logger.error(f"Payment confirmation failed: {stripe_error}")
                payment.status = 'payment_failed'
                db.session.commit()
                return jsonify({"error": "Payment confirmation failed", "details": str(stripe_error)}), 400

            payment.stripe_status = confirmed_intent.status

            if confirmed_intent.status in ('succeeded', 'requires_capture'):
                payment.status = 'paid'
                payment.date_held_escrow = datetime.utcnow()
                contract.hiring_fee_paid = True
                contract.payment_status = 'paid'

                # Activate contract if both signed and fee paid
                if contract.is_fully_signed():
                    contract.status = 'active'
                    logger.info(f"Contract {contract_id} activated after hiring fee payment")
                    try:
                        from app.services.notification_service import notification_service
                        from app.models.notification import NotificationType
                        from flask import url_for
                        notification_service.send_notification(
                            user_id=contract.worker_id,
                            notification_type=NotificationType.CONTRACT_AWARDED,
                            title="Contract is Now Active!",
                            content=f"The contract for '{contract.job.title}' is now active. You can start work!",
                            priority=1,
                            category="contract",
                            action_url=url_for('contract_review', contract_id=contract.id, _external=True)
                        )
                    except Exception as e:
                        logger.error(f"Failed to send activation notification: {e}")

            elif confirmed_intent.status == 'requires_action':
                payment.status = 'requires_action'
                db.session.commit()
                return jsonify({
                    "requires_action": True,
                    "payment_intent_client_secret": confirmed_intent.client_secret,
                    "payment_intent_id": confirmed_intent.id
                }), 200
            else:
                payment.status = 'payment_failed'
                db.session.commit()
                return jsonify({"error": "Payment failed", "status": confirmed_intent.status}), 400

            db.session.commit()

            return jsonify({
                "message": "Hiring fee paid successfully - contract activated",
                "payment": {
                    "id": payment.id,
                    "payment_reference": payment.payment_reference,
                    "gross_amount": 55.00,
                    "platform_fee": 50.00,
                    "gst_amount": 5.00,
                    "status": payment.status
                },
                "contract": {
                    "id": contract.id,
                    "status": contract.status
                }
            }), 201

        except Exception as db_error:
            db.session.rollback()
            logger.error(f"Database error during payment: {db_error}")
            raise

    except Exception as e:
        db.session.rollback()
        logger.error(f"Payment processing failed: {str(e)}", exc_info=True)
        return jsonify({"error": f"Payment processing failed: {str(e)}"}), 500


@legal_bp.route('/contract/<int:contract_id>/mark-complete', methods=['POST'])
@jwt_required()
def mark_contract_complete(contract_id):
    """Worker marks contract work as complete"""
    try:
        current_user_id = get_jwt_identity()
        
        contract = Contract.query.get_or_404(contract_id)
        
        # Only worker can mark as complete
        if contract.worker_id != current_user_id:
            return jsonify({"error": "Only the worker can mark work as complete"}), 403
        
        if contract.status != 'active':
            return jsonify({"error": "Contract must be active to mark complete"}), 400
        
        # Update contract status
        contract.status = 'pending_review'
        
        # Find associated payment
        payment = contract.payments.filter_by(status='held_escrow').first()
        if payment:
            payment.status = 'pending_release'
            payment.release_conditions_met = True
        
        db.session.commit()
        
        return jsonify({
            "message": "Work marked as complete - awaiting contractor review",
            "contract_status": contract.status,
            "payment_status": payment.status if payment else None
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": f"Failed to mark complete: {str(e)}"}), 500


@legal_bp.route('/contract/<int:contract_id>/approve-completion', methods=['POST'])
@jwt_required()
def approve_contract_completion(contract_id):
    """Contractor approves work completion (no escrow release needed with flat fee model)"""
    try:
        current_user_id = get_jwt_identity()

        contract = Contract.query.get_or_404(contract_id)

        if contract.contractor_id != current_user_id:
            return jsonify({"error": "Only the contractor can approve completion"}), 403

        if contract.status != 'pending_review':
            return jsonify({"error": "Contract is not pending completion review"}), 400

        # Simply mark contract as completed - no payment transfer needed
        contract.mark_as_completed()
        db.session.commit()

        return jsonify({
            "message": "Work approved - contract completed successfully",
            "contract_status": contract.status
        }), 200

    except Exception as e:
        db.session.rollback()
        return jsonify({"error": f"Failed to approve completion: {str(e)}"}), 500


@legal_bp.route('/contract/<int:contract_id>/dispute-completion', methods=['POST'])
@jwt_required()
def dispute_contract_completion(contract_id):
    """Contractor disputes work completion"""
    try:
        current_user_id = get_jwt_identity()
        data = request.get_json()
        
        contract = Contract.query.get_or_404(contract_id)
        
        # Only contractor can dispute
        if contract.contractor_id != current_user_id:
            return jsonify({"error": "Only the contractor can dispute completion"}), 403
        
        if contract.status != 'pending_review':
            return jsonify({"error": "Contract is not pending completion review"}), 400
        
        dispute_reason = data.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()
        
        return jsonify({
            "message": "Completion disputed - contract requires resolution",
            "contract_status": contract.status,
            "dispute_reason": dispute_reason,
            "next_steps": "Contact support or resolve directly with worker"
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": f"Failed to dispute completion: {str(e)}"}), 500


@legal_bp.route('/contract/<int:contract_id>/cancel', methods=['POST'])
@jwt_required()
def cancel_contract(contract_id):
    """Cancel contract and refund payment if applicable"""
    try:
        from ..services.stripe_service import stripe_service
        
        current_user_id = get_jwt_identity()
        data = request.get_json()
        
        contract = Contract.query.get_or_404(contract_id)
        
        # Both parties can cancel under certain conditions
        if contract.contractor_id != current_user_id and contract.worker_id != current_user_id:
            return jsonify({"error": "Unauthorized to cancel this contract"}), 403
        
        if contract.status in ['completed', 'cancelled']:
            return jsonify({"error": "Contract cannot be cancelled"}), 400
        
        cancellation_reason = data.get('reason', 'Contract cancelled by agreement')
        
        # Handle payment refund if exists
        payment = contract.payments.filter_by(status='held_escrow').first()
        if payment and payment.stripe_payment_intent_id:
            # Refund the payment
            refund = stripe_service.refund_payment(
                payment.stripe_payment_intent_id,
                reason='requested_by_customer'
            )
            payment.status = 'refunded'
            payment.stripe_status = 'refunded'
        
        # Update contract status
        contract.status = 'cancelled'
        
        db.session.commit()
        
        return jsonify({
            "message": "Contract cancelled successfully",
            "contract_status": contract.status,
            "payment_refunded": payment.status == 'refunded' if payment else False,
            "cancellation_reason": cancellation_reason
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": f"Failed to cancel contract: {str(e)}"}), 500


@legal_bp.route('/payments/<int:payment_id>/status', methods=['GET'])
@jwt_required()
def get_payment_status(payment_id):
    """Get current payment status and details"""
    try:
        current_user_id = get_jwt_identity()
        
        payment = Payment.query.get_or_404(payment_id)
        contract = payment.contract
        
        # Check authorization
        if contract.contractor_id != current_user_id and contract.worker_id != current_user_id:
            return jsonify({"error": "Unauthorized to view this payment"}), 403
        
        return jsonify({
            "payment": {
                "id": payment.id,
                "reference": payment.payment_reference,
                "status": payment.status,
                "gross_amount": float(payment.gross_amount),
                "platform_fee": float(payment.platform_fee),
                "net_to_worker": float(payment.net_to_worker),
                "date_initiated": payment.date_initiated.isoformat(),
                "date_held_escrow": payment.date_held_escrow.isoformat() if payment.date_held_escrow else None,
                "date_released": payment.date_released.isoformat() if payment.date_released else None,
                "dispute_deadline": payment.dispute_deadline.isoformat() if payment.dispute_deadline else None,
                "stripe_status": payment.stripe_status
            },
            "contract_status": contract.status
        }), 200
        
    except Exception as e:
        return jsonify({"error": f"Failed to get payment status: {str(e)}"}), 500


@legal_bp.route('/stripe/webhook', methods=['POST'])
@limiter.limit("100 per minute")  # Rate limit webhooks to prevent DoS
@csrf.exempt  # Webhooks don't use CSRF tokens - use Stripe signature instead
def stripe_webhook():
    """Handle Stripe webhooks"""
    from .stripe_webhooks import handle_stripe_webhook
    return handle_stripe_webhook()


@legal_bp.route('/invoices', methods=['POST'])
@jwt_required()
def generate_invoice():
    """Generate GST-compliant invoice"""
    try:
        current_user_id = get_jwt_identity()
        data = request.get_json()
        
        if not data.get('payment_id'):
            return jsonify({"error": "payment_id is required"}), 400
        
        payment = Payment.query.get(data['payment_id'])
        if not payment:
            return jsonify({"error": "Payment not found"}), 404
        
        contract = payment.contract
        
        # Check if user is the worker (invoice issuer)
        if contract.worker_id != current_user_id:
            return jsonify({"error": "Only the worker can generate invoices"}), 403
        
        # Check if worker is GST registered
        worker = User.query.get(contract.worker_id)
        if not worker.gst_registered:
            return jsonify({"error": "Worker must be GST registered to issue invoices"}), 400
        
        # Use the auto_generate_invoice method for consistency
        invoice = payment.auto_generate_invoice()
        
        if not invoice:
            return jsonify({"error": "Failed to generate invoice. Invoice may already exist or payment data is invalid."}), 400
        
        db.session.commit()
        
        return jsonify({
            "message": "GST invoice generated successfully",
            "invoice": {
                "id": invoice.id,
                "invoice_number": invoice.invoice_number,
                "amount_ex_gst": float(invoice.amount_ex_gst),
                "gst_amount": float(invoice.gst_amount),
                "total_amount": float(invoice.total_amount),
                "due_date": invoice.due_date.isoformat(),
                "supplier_abn": invoice.supplier_abn,
                "buyer_abn": invoice.buyer_abn
            }
        }), 201
        
    except Exception as e:
        db.session.rollback()
        return jsonify({"error": f"Invoice generation failed: {str(e)}"}), 500


@legal_bp.route('/validate-abn', methods=['POST'])
def validate_abn():
    """Validate Australian Business Number"""
    try:
        data = request.get_json()
        abn = data.get('abn')
        
        if not abn:
            return jsonify({"error": "ABN is required"}), 400
        
        from ...utils.validators import validate_abn
        is_valid = validate_abn(abn)
        
        # Check if ABN is registered with a user
        user = User.query.filter_by(abn_number=abn).first()
        gst_registered = user.gst_registered if user else False
        
        # Calculate withholding tax requirement
        withholding_required = not gst_registered
        
        return jsonify({
            "abn": abn,
            "is_valid": is_valid,
            "gst_registered": gst_registered,
            "withholding_tax_required": withholding_required,
            "registered_user": bool(user)
        })
        
    except Exception as e:
        return jsonify({"error": f"ABN validation failed: {str(e)}"}), 500
