from datetime import datetime, timezone, timedelta
from flask import render_template, request, jsonify, current_app, flash, redirect, url_for
from flask_mail import Message

from app.services import services_bp
from app.services.forms import ProjectEnquiryForm
from app.models import ProjectEnquiry
from app.extensions import db, mail


def get_client_ip():
    """Retrieve real client IP behind reverse proxies safely."""
    forwarded_for = request.headers.get('X-Forwarded-For')
    if forwarded_for:
        return forwarded_for.split(',')[0].strip()
    return request.remote_addr or "127.0.0.1"


def extract_first_error(err_data):
    """Safely retrieve the first error message string to clear Pylance type warnings."""
    if isinstance(err_data, dict):
        return str(next(iter(err_data.values()), "Invalid input"))
    if isinstance(err_data, (list, tuple)) and err_data:
        return str(err_data[0])
    return "Invalid input"


@services_bp.route("/services", methods=["GET", "POST"], endpoint="index")
def index():
    return render_template("pages/services.html")


@services_bp.route("/services/submit", methods=["POST"], endpoint="submit_enquiry")
def submit_enquiry():
    form = ProjectEnquiryForm()
    client_ip = get_client_ip()
    one_hour_ago = datetime.now(timezone.utc) - timedelta(hours=1)

    # 1. Check IP Rate Limit (1 submission per hour)
    recent_submission = ProjectEnquiry.query.filter(
        ProjectEnquiry.ip_address == client_ip,
        ProjectEnquiry.created_at >= one_hour_ago
    ).order_by(ProjectEnquiry.created_at.desc()).first()

    if recent_submission:
        created_at = recent_submission.created_at
        if created_at.tzinfo is None:
            created_at = created_at.replace(tzinfo=timezone.utc)

        time_passed = datetime.now(timezone.utc) - created_at
        seconds_remaining = int(3600 - time_passed.total_seconds())
        minutes_remaining = max(1, (seconds_remaining + 59) // 60)

        err_msg = f"You can only submit one project enquiry per hour. Please wait {minutes_remaining} minute(s) before trying again."

        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return jsonify({'success': False, 'message': err_msg}), 429

        flash(err_msg, 'warning')
        return redirect(url_for('services.index'))

    # 2. Process Validated Form
    if form.validate_on_submit():
        try:
            enquiry = ProjectEnquiry(
                service=form.service.data,
                project_title=form.project_title.data,
                description=form.description.data,
                name=form.name.data,
                email=form.email.data,
                phone=form.phone.data,
                timeline=form.timeline.data,
                ip_address=client_ip
            )
            db.session.add(enquiry)
            db.session.commit()

            send_project_enquiry_emails(enquiry)

            success_msg = "Thank you! Your project enquiry has been submitted successfully."

            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return jsonify({'success': True, 'message': success_msg}), 200

            flash(success_msg, 'success')
            return redirect(url_for('services.index'))

        except Exception as e:
            db.session.rollback()
            current_app.logger.error(f"Project enquiry submission failed: {e}")
            err_msg = "An internal server error occurred. Please try again."

            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return jsonify({'success': False, 'message': err_msg}), 500

            flash(err_msg, 'danger')
            return redirect(url_for('services.index'))

    # 3. Handle Form Validation Errors (AJAX)
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        formatted_errors = {
            field: extract_first_error(err_data)
            for field, err_data in form.errors.items()
        }
        return jsonify({'success': False, 'errors': formatted_errors}), 400

    # Fallback for standard form posts with errors
    first_error = extract_first_error(next(iter(form.errors.values()), "Please check the form fields."))
    flash(first_error, 'danger')
    return redirect(url_for('services.index'))


def send_project_enquiry_emails(enquiry):
    """Sends notification to contact@codnesta.com and confirmation email to sender."""
    try:
        admin_email = (
            current_app.config.get('ADMIN_EMAIL') 
            or current_app.config.get('MAIL_DEFAULT_SENDER') 
            or "contact@codnesta.com"
        )

        admin_msg = Message(
            subject=f"[Project Enquiry] {enquiry.service} - {enquiry.project_title} ({enquiry.name})",
            recipients=[str(admin_email)],
            body=f"Service: {enquiry.service}\nProject Title: {enquiry.project_title}\n\nDescription:\n{enquiry.description}\n\nClient Name: {enquiry.name}\nEmail: {enquiry.email}\nPhone: {enquiry.phone or 'N/A'}\nTimeline: {enquiry.timeline or 'N/A'}"
        )

        user_msg = Message(
            subject="We've received your project enquiry | CodNesta",
            recipients=[str(enquiry.email)],
            body=f"Hello {enquiry.name},\n\nThank you for reaching out to CodNesta regarding your project '{enquiry.project_title}'. Our technical team has received your details and will review your requirements to get back to you within 24 hours.\n\nBest regards,\nCodNesta Team"
        )

        # Safe HTML Template Rendering (Attaches HTML if templates exist and render cleanly)
        try:
            formatted_date = datetime.now(timezone.utc).strftime("%B %d, %Y at %I:%M %p UTC")
            current_year = datetime.now().year

            admin_msg.html = render_template(
                "emails/service/admin_enquiry_notification.html",
                name=enquiry.name,
                email=enquiry.email,
                phone=enquiry.phone,
                service=enquiry.service,
                project_title=enquiry.project_title,
                timeline=enquiry.timeline,
                description=enquiry.description,
                created_at=formatted_date
            )

            user_msg.html = render_template(
                "emails/service/client_enquiry_confirmation.html",
                name=enquiry.name,
                email=enquiry.email,
                phone=enquiry.phone,
                service=enquiry.service,
                project_title=enquiry.project_title,
                timeline=enquiry.timeline,
                current_year=current_year
            )
        except Exception as render_err:
            current_app.logger.warning(f"Could not render HTML email templates, sending plain text fallback: {render_err}")

        mail.send(admin_msg)
        mail.send(user_msg)
    except Exception as e:
        current_app.logger.error(f"Failed to send project enquiry emails: {e}")