import re
import threading
from datetime import datetime
from io import BytesIO
from pathlib import Path

from flask import Blueprint, jsonify, render_template, request, session, redirect, url_for
from mysql.connector import Error, IntegrityError

from app.aws_services import AWSService, UnsupportedImageError
from app.models.database import get_db_connection
from config.aws_config import get_aws_settings, get_s3_client
from models.user_model import (
    create_event_image,
    create_registered_user,
    create_user,
    get_latest_event,
    get_site_assets,
    get_user_by_email_or_phone,
    get_visitor_registration_by_identifier,
)
from scripts.generate_and_store_token import generate_and_store_token

main_blueprint = Blueprint("main", __name__)


def is_valid_email(email):
    return bool(re.match(r"^[^@\s]+@[^@\s]+\.[^@\s]+$", email or ""))


def build_registration_s3_key(visitor_id, filename):
    extension = Path(filename or "capture.jpg").suffix.lower() or ".jpg"
    timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
    return f"users/visitor_{visitor_id}_{timestamp}{extension}"


def upload_registration_image_to_s3(image_file, visitor_id):
    try:
        settings = get_aws_settings()
        s3_client = get_s3_client()
        s3_key = build_registration_s3_key(visitor_id, image_file.filename)
        file_bytes = image_file.read()
        if not file_bytes:
            raise ValueError("Uploaded image is empty.")
        s3_client.upload_fileobj(
            Fileobj=BytesIO(file_bytes),
            Bucket=settings.s3_bucket,
            Key=s3_key,
            ExtraArgs={"ContentType": image_file.content_type or "image/jpeg"},
        )
    except Exception as exc:
        raise RuntimeError(f"Failed to upload registration image to S3: {exc}") from exc

    image_url = f"https://{settings.s3_bucket}.s3.{settings.region}.amazonaws.com/{s3_key}"
    return {"s3_key": s3_key, "image_url": image_url}


@main_blueprint.route("/", methods=["GET"])
def home():
    return jsonify(
        {
            "message": "AI Event Photo Delivery API is running.",
            "routes": [
                "GET /register",
                "POST /api/register",
                "GET /upload",
                "POST /api/upload-event-images",
                "GET /health",
            ],
        }
    )


@main_blueprint.route("/register", methods=["GET"])
def register_page():
    site_assets = get_site_assets()
    event_data = get_latest_event()
    return render_template(
        "register.html",
        logo_image=site_assets["logo"]["image_path"] if site_assets["logo"] else None,
        header_image=site_assets["header"]["image_path"] if site_assets["header"] else None,
        footer_image=site_assets["footer"]["image_path"] if site_assets["footer"] else None,
        event_data=event_data,
    )


@main_blueprint.route("/register/manual", methods=["GET"])
def register_manual():
    site_assets = get_site_assets()
    event_data = get_latest_event()
    return render_template(
        "manual.html",
        logo_image=site_assets["logo"]["image_path"] if site_assets.get("logo") else None,
        header_image=site_assets["header"]["image_path"] if site_assets.get("header") else None,
        footer_image=site_assets["footer"]["image_path"] if site_assets.get("footer") else None,
        event_data=event_data,
    )


@main_blueprint.route("/register/qr", methods=["GET"])
def register_qr():
    site_assets = get_site_assets()
    event_data = get_latest_event()
    return render_template(
        "qr.html",
        logo_image=site_assets["logo"]["image_path"] if site_assets.get("logo") else None,
        header_image=site_assets["header"]["image_path"] if site_assets.get("header") else None,
        footer_image=site_assets["footer"]["image_path"] if site_assets.get("footer") else None,
        event_data=event_data,
    )


@main_blueprint.route("/upload", methods=["GET"])
def upload_page():
    # Not logged in → go to login
    if not session.get("user_id"):
        return redirect(url_for("auth.login"))

    role = session.get("role") or session.get("admin_role") or ""

    if role == "admin":
        return redirect("/admin/dashboard")
    elif role == "sub_admin":
        return redirect("/subadmin/dashboard")
    elif role == "photographer":
        site_assets = get_site_assets()
        return render_template(
            "upload.html",
            logo_image=site_assets["logo"]["image_path"] if site_assets["logo"] else None,
            header_image=site_assets["header"]["image_path"] if site_assets["header"] else None,
            footer_image=site_assets["footer"]["image_path"] if site_assets["footer"] else None,
        )
    else:
        # Unknown or corrupt role — wipe session, send to login fresh (breaks redirect loop)
        session.clear()
        return redirect(url_for("auth.login"))


@main_blueprint.route("/health", methods=["GET"])
def health():
    return jsonify({"status": "ok"})


@main_blueprint.route("/api/check-file", methods=["GET"])
def check_file():
    filename = (request.args.get("name") or "").strip()
    if not filename:
        return jsonify({"error": "name is required"}), 400

    try:
        aws_service = AWSService()
        return jsonify({"exists": aws_service.event_image_exists(filename)})
    except RuntimeError as exc:
        return jsonify({"error": str(exc)}), 500


@main_blueprint.route("/api/register", methods=["POST"])
def register_user():
    identifier = request.form.get("identifier", "").strip()
    image = request.files.get("image")

    if not identifier or not image:
        return jsonify({"error": "identifier and image are required."}), 400

    visitor = get_visitor_registration_by_identifier(identifier)
    if not visitor:
        return jsonify({"error": "Visitor not found in visitors_registration."}), 404

    name = (visitor.get("name") or "").strip()
    email = (visitor.get("email") or "").strip().lower()
    phone = (visitor.get("mobile_number") or "").strip()

    if not name:
        return jsonify({"error": "Matched visitor record does not have a name."}), 400

    if email and not is_valid_email(email):
        return jsonify({"error": "Matched visitor email is invalid."}), 400

    existing_user = get_user_by_email_or_phone(email=email, phone=phone)
    if existing_user:
        return (
            jsonify(
                {
                    "error": "This visitor is already registered in users.",
                    "user_id": existing_user["id"],
                    "name": existing_user["name"],
                    "email": existing_user["email"],
                    "phone": existing_user["phone"],
                    "image_url": existing_user.get("image_url") or existing_user.get("s3_image_url"),
                }
            ),
            409,
        )

    try:
        upload_result = upload_registration_image_to_s3(image, visitor["id"])
        user_id = create_registered_user(
            name=name,
            email=email or None,
            phone=phone or None,
            image_url=upload_result["image_url"],
            s3_image_key=upload_result["s3_key"],
        )
        user_token = generate_and_store_token(user_id)

        def _index_face_bg(uid, s3_key):
            try:
                from app.aws_services import AWSService
                from models.user_model import update_user_face_id
                aws = AWSService()
                face_id = aws.index_user_face(s3_key, str(uid))
                if face_id:
                    update_user_face_id(uid, face_id)
                    print(f"[bg] Face indexed for user_id={uid} face_id={face_id}")
            except Exception as exc:
                print(f"[bg] Face indexing failed for user_id={uid}: {exc}")

        threading.Thread(
            target=_index_face_bg,
            args=(user_id, upload_result["s3_key"]),
            daemon=True
        ).start()

    except IntegrityError:
        return jsonify({"error": "A user with this email already exists."}), 409
    except ValueError as exc:
        return jsonify({"error": str(exc)}), 400
    except (RuntimeError, Error) as exc:
        return jsonify({"error": str(exc)}), 500
    except Exception as exc:
        return jsonify({"error": f"Unexpected registration error: {exc}"}), 500

    return (
        jsonify(
            {
                "success": True,
                "message": "Visitor registered successfully",
                "user_id": user_id,
                "access_token": user_token,
                "name": name,
                "email": email,
                "phone": phone,
                "image_url": upload_result["image_url"],
            }
        ),
        201,
    )


@main_blueprint.route("/api/visitor-lookup", methods=["GET"])
def visitor_lookup():
    identifier = (request.args.get("identifier") or "").strip()

    if not identifier:
        return jsonify({"error": "Missing identifier"})

    conn = get_db_connection()
    if conn is None:
        return jsonify({"error": "Database connection failed"})

    cursor = conn.cursor(dictionary=True)

    try:
        cursor.execute("""
            SELECT id, name, email, mobile_number
            FROM visitors_registration
            WHERE email = %s
               OR mobile_number = %s
               OR LOWER(name) = LOWER(%s)
        """, (identifier, identifier, identifier))

        visitors = cursor.fetchall()

        if not visitors:
            return jsonify({"found": False})

        if len(visitors) > 1:
            return jsonify({
                "found": True,
                "multiple": True,
                "visitors": [
                    {
                        "id": v["id"],
                        "name": v.get("name", ""),
                        "email": v.get("email", ""),
                        "phone": v.get("mobile_number", "")
                    }
                    for v in visitors
                ]
            })

        visitor = visitors[0]

        cursor.execute("""
            SELECT s3_image_url
            FROM users
            WHERE email = %s OR phone = %s
        """, (visitor.get("email") or "", visitor.get("mobile_number") or ""))

        user = cursor.fetchone()

        visitor_data = {
            "id": visitor["id"],
            "name": visitor.get("name", ""),
            "email": visitor.get("email", ""),
            "phone": visitor.get("mobile_number", "")
        }

        if user:
            return jsonify({
                "found": True,
                "multiple": False,
                "already_registered": True,
                "visitor": visitor_data,
                "image_url": user.get("s3_image_url") or ""
            })

        return jsonify({
            "found": True,
            "multiple": False,
            "already_registered": False,
            "visitor": visitor_data
        })

    except Exception as e:
        print("ERROR in visitor-lookup:", e)
        return jsonify({"error": str(e)})

    finally:
        cursor.close()
        conn.close()


@main_blueprint.route("/api/visitor-search", methods=["GET"])
def visitor_search():
    """Predictive search — returns up to 8 matching visitors as user types."""
    q = (request.args.get("q") or "").strip()
    if len(q) < 1:
        return jsonify([])

    conn = get_db_connection()
    if conn is None:
        return jsonify([])

    cursor = conn.cursor(dictionary=True)
    try:
        like = f"%{q}%"
        cursor.execute("""
            SELECT id, name, email, mobile_number
            FROM visitors_registration
            WHERE LOWER(name)   LIKE LOWER(%s)
               OR LOWER(email)  LIKE LOWER(%s)
               OR mobile_number LIKE %s
            ORDER BY name ASC
            LIMIT 8
        """, (like, like, like))
        rows = cursor.fetchall()
        return jsonify([
            {
                "id": r["id"],
                "name": r.get("name", ""),
                "email": r.get("email", ""),
                "phone": r.get("mobile_number", "")
            }
            for r in rows
        ])
    except Exception as e:
        print("ERROR in visitor-search:", e)
        return jsonify([])
    finally:
        cursor.close()
        conn.close()


@main_blueprint.route("/api/upload-event-images", methods=["POST"])
def upload_event_images():
    images = request.files.getlist("images")
    day_event_id = request.form.get("day_event_id")

    if not images:
        return jsonify({"error": "Please upload at least one event image."}), 400

    if not day_event_id:
        return jsonify({"error": "Please select an event before uploading images."}), 400

    try:
        day_event_id = int(day_event_id)
    except (ValueError, TypeError):
        return jsonify({"error": "Invalid event selected."}), 400

    aws_service = AWSService()
    uploaded_items = []
    skipped_files = []

    try:
        for image in images:
            try:
                upload_result = aws_service.upload_file_object(
                    file_object=image,
                    folder_name="events",
                    original_filename=image.filename,
                )
                image_id = create_event_image(
                    original_s3_key=upload_result["original_s3_key"],
                    processed_s3_key=upload_result["processed_s3_key"],
                    original_url=upload_result["original_url"],
                    processed_url=upload_result["processed_url"],
                    day_event_id=day_event_id,
                )
                uploaded_items.append(
                    {
                        "image_id": image_id,
                        "original_url": upload_result["original_url"],
                        "processed_url": upload_result["processed_url"],
                        "original_s3_key": upload_result["original_s3_key"],
                        "processed_s3_key": upload_result["processed_s3_key"],
                        "day_event_id": day_event_id,
                    }
                )

                # Push to background face-match queue
                try:
                    from app import match_queue
                    match_queue.put({
                        "processed_s3_key": upload_result["processed_s3_key"],
                        "event_image_id": image_id,
                    })
                except Exception:
                    pass

            except UnsupportedImageError as exc:
                skipped_files.append(
                    {
                        "filename": image.filename,
                        "reason": str(exc),
                    }
                )
    except (RuntimeError, Error) as exc:
        return jsonify({"error": str(exc)}), 500

    if not uploaded_items and skipped_files:
        return (
            jsonify(
                {
                    "error": "No event images were uploaded.",
                    "skipped_files": skipped_files,
                }
            ),
            400,
        )

    return (
        jsonify(
            {
                "message": "Event images uploaded successfully.",
                "uploaded_images": uploaded_items,
                "skipped_files": skipped_files,
            }
        ),
        201,
    )


@main_blueprint.route("/api/event-details", methods=["GET"])
def event_details_api():
    """API endpoint to get event details and assets."""
    try:
        event_data = get_latest_event()
        site_assets = get_site_assets()
        response = {
            "event": event_data or {},
            "assets": {
                "logo_image":   site_assets.get("logo",   {}).get("image_path") if site_assets.get("logo")   else None,
                "header_image": site_assets.get("header", {}).get("image_path") if site_assets.get("header") else None,
                "footer_image": site_assets.get("footer", {}).get("image_path") if site_assets.get("footer") else None,
            }
        }
        return jsonify(response), 200

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