import os
import numpy as np
from celery_app import app
from config import settings
from models.matcher import compute_similarity
from models.vision_model import estimate_door_positions
from utils.image_utils import load_equirectangular_image
from sqlalchemy import create_engine, text
from sqlalchemy.orm import Session


@app.task(bind=True)
def detect_connections(self, house_id: str):
    """Detect which panoramas are connected."""
    engine = create_engine(settings.database_url)

    try:
        with Session(engine) as session:
            # Load all panoramas for house
            result = session.execute(
                text(
                    "SELECT id, file_path, capture_order FROM panoramas "
                    "WHERE house_id = :house_id ORDER BY capture_order ASC"
                ),
                {"house_id": house_id},
            )
            panoramas = result.fetchall()

            if len(panoramas) < 2:
                return {
                    "success": True,
                    "connections": [],
                    "message": "Less than 2 panoramas, no connections to detect",
                }

            # Build lookup maps
            pano_map = {p[0]: {"path": p[1], "order": p[2]} for p in panoramas}
            pano_ids = [p[0] for p in panoramas]
            n = len(pano_ids)

            connections = []
            evaluated_pairs = set()

            for i in range(n):
                source_id = pano_ids[i]
                source_info = pano_map[source_id]

                # Determine candidates:
                # 1. Sequence neighbors (capture_order +/- 1)
                # 2. Same room panos within +/- 2 sequence distance
                candidates = []
                for j in range(n):
                    if i == j:
                        continue
                    target_id = pano_ids[j]
                    target_info = pano_map[target_id]
                    order_diff = abs(
                        source_info["order"] - target_info["order"]
                    )
                    if order_diff <= 1:
                        # Direct sequence neighbor - always evaluate
                        candidates.append(target_id)
                    elif order_diff <= 2:
                        # Within +/- 2 - evaluate
                        candidates.append(target_id)

                for target_id in candidates:
                    pair_key = tuple(sorted([source_id, target_id]))
                    if pair_key in evaluated_pairs:
                        continue
                    evaluated_pairs.add(pair_key)

                    source_path = os.path.join(
                        settings.upload_dir, source_info["path"]
                    )
                    target_path = os.path.join(
                        settings.upload_dir, pano_map[target_id]["path"]
                    )

                    if not os.path.exists(source_path) or not os.path.exists(
                        target_path
                    ):
                        continue

                    # Compute image similarity
                    similarity = compute_similarity(source_path, target_path)

                    # Run door detection on source image
                    source_img = np.array(
                        load_equirectangular_image(source_path)
                    )
                    doors = estimate_door_positions(source_img)

                    # Determine connection yaw
                    connection_yaw = None
                    if doors and similarity > 0.3:
                        # Use first detected door yaw
                        connection_yaw = doors[0][0]

                    # Suggest connection if similarity is above threshold
                    if similarity > settings.confidence_threshold:
                        confidence = similarity
                    elif similarity > 0.3:
                        confidence = similarity
                    else:
                        continue

                    connections.append(
                        {
                            "from_pano_id": source_id,
                            "to_pano_id": target_id,
                            "yaw": connection_yaw,
                            "pitch": -20,
                            "type": "door",
                            "confidence": float(confidence),
                            "similarity": float(similarity),
                        }
                    )

            # Save AI suggestions to database
            # Clear old suggestions
            session.execute(
                text(
                    "DELETE FROM ai_suggestions WHERE house_id = :house_id "
                    "AND suggestion_type = 'connection'"
                ),
                {"house_id": house_id},
            )

            for conn in connections:
                session.execute(
                    text(
                        "INSERT INTO ai_suggestions (house_id, suggestion_type, "
                        "data, confidence, status) "
                        "VALUES (:house_id, 'connection', :data, :confidence, 'pending')"
                    ),
                    {
                        "house_id": house_id,
                        "data": str(conn),
                        "confidence": conn["confidence"],
                    },
                )

            session.commit()

    except Exception as e:
        return {"success": False, "connections": [], "error": str(e)}

    return {
        "success": True,
        "connections": connections,
    }
