"""BAN YARO — Playdate-Matching"""

import math
import logging
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from typing import Optional
from database import db
from auth import get_current_user

router = APIRouter()
logger = logging.getLogger(__name__)


# ------------------------------------------------------------------
# Haversine
# ------------------------------------------------------------------
def _haversine(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
    R = 6371.0
    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = (math.sin(dlat / 2) ** 2
         + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2))
         * math.sin(dlon / 2) ** 2)
    return R * 2 * math.asin(math.sqrt(a))


def _calc_alter(geburtstag: Optional[str]) -> Optional[str]:
    """Gibt lesbares Alter zurück z.B. '2 Jahre' oder '5 Monate'."""
    if not geburtstag:
        return None
    try:
        from datetime import date
        geb = date.fromisoformat(geburtstag[:10])
        today = date.today()
        monate = (today.year - geb.year) * 12 + (today.month - geb.month)
        if today.day < geb.day:
            monate -= 1
        if monate < 0:
            return None
        if monate < 24:
            return f"{monate} {'Monat' if monate == 1 else 'Monate'}"
        jahre = monate // 12
        return f"{jahre} {'Jahr' if jahre == 1 else 'Jahre'}"
    except Exception:
        return None


# ------------------------------------------------------------------
# Schemas
# ------------------------------------------------------------------
class ListingUpsert(BaseModel):
    dog_id:      int
    lat:         float
    lon:         float
    ort_name:    Optional[str] = None
    radius_km:   int = 10
    beschreibung: Optional[str] = None


class RequestCreate(BaseModel):
    to_dog_id: int
    nachricht: Optional[str] = None


class RequestPatch(BaseModel):
    status: str  # accepted | declined


# ------------------------------------------------------------------
# Helpers — Konversation für Playdate öffnen (ohne Freundschaftspflicht)
# ------------------------------------------------------------------
def _ensure_conversation(conn, user_a: int, user_b: int) -> int:
    a, b = (min(user_a, user_b), max(user_a, user_b))
    existing = conn.execute(
        "SELECT id FROM conversations WHERE user_a_id=? AND user_b_id=?",
        (a, b)
    ).fetchone()
    if existing:
        return existing["id"]
    cur = conn.execute(
        "INSERT INTO conversations (user_a_id, user_b_id) VALUES (?,?)",
        (a, b)
    )
    return cur.lastrowid


# ------------------------------------------------------------------
# Routes
# ------------------------------------------------------------------

@router.get("/nearby")
async def nearby(lat: float, lon: float, radius: int = 10,
                 user=Depends(get_current_user)):
    uid = user["id"]
    with db() as conn:
        rows = conn.execute("""
            SELECT pl.id AS listing_id,
                   pl.lat, pl.lon, pl.ort_name, pl.beschreibung,
                   d.id AS dog_id, d.name AS dog_name, d.rasse,
                   d.geburtstag, d.foto_url, d.geschlecht
            FROM playdate_listings pl
            JOIN dogs d ON d.id = pl.dog_id
            WHERE pl.aktiv = 1
              AND pl.user_id != ?
        """, (uid,)).fetchall()

    result = []
    for r in rows:
        dist = _haversine(lat, lon, r["lat"], r["lon"])
        if dist <= radius:
            result.append({
                "listing_id":    r["listing_id"],
                "dog_id":        r["dog_id"],
                "dog_name":      r["dog_name"],
                "rasse":         r["rasse"],
                "alter":         _calc_alter(r["geburtstag"]),
                "geschlecht":    r["geschlecht"],
                "foto_url":      r["foto_url"],
                "ort_name":      r["ort_name"],
                "beschreibung":  r["beschreibung"],
                "entfernung_km": round(dist, 1),
            })

    result.sort(key=lambda x: x["entfernung_km"])
    return result


@router.put("/listing", status_code=200)
async def upsert_listing(data: ListingUpsert, user=Depends(get_current_user)):
    uid = user["id"]
    with db() as conn:
        # Sicherstellen dass der Hund dem User gehört
        dog = conn.execute(
            "SELECT id FROM dogs WHERE id=? AND user_id=?",
            (data.dog_id, uid)
        ).fetchone()
        if not dog:
            raise HTTPException(404, "Hund nicht gefunden.")

        existing = conn.execute(
            "SELECT id FROM playdate_listings WHERE dog_id=?",
            (data.dog_id,)
        ).fetchone()

        if existing:
            conn.execute("""
                UPDATE playdate_listings
                   SET lat=?, lon=?, ort_name=?, radius_km=?, beschreibung=?,
                       aktiv=1, updated_at=datetime('now')
                 WHERE dog_id=?
            """, (data.lat, data.lon, data.ort_name, data.radius_km,
                  data.beschreibung, data.dog_id))
            return {"ok": True, "id": existing["id"]}
        else:
            cur = conn.execute("""
                INSERT INTO playdate_listings
                    (dog_id, user_id, lat, lon, ort_name, radius_km, beschreibung)
                VALUES (?,?,?,?,?,?,?)
            """, (data.dog_id, uid, data.lat, data.lon, data.ort_name,
                  data.radius_km, data.beschreibung))
            return {"ok": True, "id": cur.lastrowid}


@router.delete("/listing/{dog_id}", status_code=200)
async def deactivate_listing(dog_id: int, user=Depends(get_current_user)):
    uid = user["id"]
    with db() as conn:
        row = conn.execute(
            "SELECT id FROM playdate_listings WHERE dog_id=? AND user_id=?",
            (dog_id, uid)
        ).fetchone()
        if not row:
            raise HTTPException(404, "Inserat nicht gefunden.")
        conn.execute(
            "UPDATE playdate_listings SET aktiv=0, updated_at=datetime('now') WHERE dog_id=?",
            (dog_id,)
        )
    return {"ok": True}


@router.get("/my-listing/{dog_id}")
async def my_listing(dog_id: int, user=Depends(get_current_user)):
    uid = user["id"]
    with db() as conn:
        row = conn.execute(
            """SELECT id, dog_id, lat, lon, ort_name, radius_km, beschreibung, aktiv
               FROM playdate_listings WHERE dog_id=? AND user_id=?""",
            (dog_id, uid)
        ).fetchone()
    if not row:
        return None
    return dict(row)


@router.post("/request", status_code=201)
async def create_request(data: RequestCreate, user=Depends(get_current_user)):
    uid = user["id"]
    with db() as conn:
        # Eigenen Hund ermitteln — nimm den ersten aktiven Hund des Users
        own_dog = conn.execute(
            "SELECT id FROM dogs WHERE user_id=? ORDER BY id LIMIT 1",
            (uid,)
        ).fetchone()
        if not own_dog:
            raise HTTPException(400, "Du hast noch keinen Hund eingetragen.")

        from_dog_id = own_dog["id"]

        # Zielhund + Besitzer prüfen
        target = conn.execute(
            "SELECT d.id, d.user_id FROM dogs d WHERE d.id=?",
            (data.to_dog_id,)
        ).fetchone()
        if not target:
            raise HTTPException(404, "Zielhund nicht gefunden.")
        if target["user_id"] == uid:
            raise HTTPException(400, "Du kannst nicht dir selbst eine Anfrage schicken.")

        to_user_id = target["user_id"]

        # Doppelte Anfrage verhindern
        existing = conn.execute(
            "SELECT id, status FROM playdate_requests WHERE from_dog_id=? AND to_dog_id=?",
            (from_dog_id, data.to_dog_id)
        ).fetchone()
        if existing:
            if existing["status"] == "pending":
                raise HTTPException(409, "Du hast bereits eine offene Anfrage an diesen Hund.")
            # Alte abgelehnte Anfrage: löschen und neu anlegen
            conn.execute(
                "DELETE FROM playdate_requests WHERE id=?",
                (existing["id"],)
            )

        cur = conn.execute("""
            INSERT INTO playdate_requests
                (from_dog_id, to_dog_id, from_user_id, to_user_id, nachricht)
            VALUES (?,?,?,?,?)
        """, (from_dog_id, data.to_dog_id, uid, to_user_id, data.nachricht))
        request_id = cur.lastrowid

        # Chat-Konversation anlegen (ohne Freundschaftspflicht)
        conv_id = _ensure_conversation(conn, uid, to_user_id)

        # Erste Nachricht mit Kontext senden
        intro = f"Hallo! Ich habe eine Playdate-Anfrage für unsere Hunde geschickt."
        if data.nachricht:
            intro += f" Meine Nachricht: {data.nachricht}"
        conn.execute("""
            INSERT INTO direct_messages (conversation_id, sender_id, text)
            VALUES (?,?,?)
        """, (conv_id, uid, intro))
        conn.execute(
            "UPDATE conversations SET last_msg_at=datetime('now') WHERE id=?",
            (conv_id,)
        )

    try:
        from routes.push import send_push_to_user
        send_push_to_user(to_user_id, {
            "title": "Playdate-Anfrage",
            "body":  f"{user['name']} möchte ein Treffen vereinbaren!",
            "type":  "playdate_request",
            "tag":   f"playdate-{request_id}",
            "data":  {"page": "playdate"},
        })
    except Exception:
        pass

    return {"ok": True, "request_id": request_id, "conversation_id": conv_id}


@router.get("/requests")
async def list_requests(user=Depends(get_current_user)):
    uid = user["id"]
    with db() as conn:
        incoming = conn.execute("""
            SELECT pr.id, pr.status, pr.nachricht, pr.created_at,
                   pr.from_user_id,
                   uf.name AS from_user_name,
                   df.name AS from_dog_name, df.rasse AS from_dog_rasse,
                   df.foto_url AS from_dog_foto,
                   df.geburtstag AS from_dog_geburtstag,
                   dt.name AS to_dog_name
            FROM playdate_requests pr
            JOIN users uf ON uf.id = pr.from_user_id
            JOIN dogs df ON df.id = pr.from_dog_id
            JOIN dogs dt ON dt.id = pr.to_dog_id
            WHERE pr.to_user_id = ?
            ORDER BY pr.created_at DESC
        """, (uid,)).fetchall()

        outgoing = conn.execute("""
            SELECT pr.id, pr.status, pr.nachricht, pr.created_at,
                   pr.to_user_id,
                   ut.name AS to_user_name,
                   dt.name AS to_dog_name, dt.rasse AS to_dog_rasse,
                   dt.foto_url AS to_dog_foto,
                   df.name AS from_dog_name
            FROM playdate_requests pr
            JOIN users ut ON ut.id = pr.to_user_id
            JOIN dogs dt ON dt.id = pr.to_dog_id
            JOIN dogs df ON df.id = pr.from_dog_id
            WHERE pr.from_user_id = ?
            ORDER BY pr.created_at DESC
        """, (uid,)).fetchall()

    def _enrich(rows, direction):
        result = []
        for r in rows:
            d = dict(r)
            d["direction"] = direction
            if direction == "incoming":
                d["alter"] = _calc_alter(d.get("from_dog_geburtstag"))
            result.append(d)
        return result

    return {
        "incoming": _enrich(incoming, "incoming"),
        "outgoing": _enrich(outgoing, "outgoing"),
    }


@router.patch("/requests/{req_id}", status_code=200)
async def patch_request(req_id: int, data: RequestPatch,
                        user=Depends(get_current_user)):
    uid = user["id"]
    if data.status not in ("accepted", "declined"):
        raise HTTPException(400, "Status muss 'accepted' oder 'declined' sein.")

    with db() as conn:
        req = conn.execute(
            "SELECT * FROM playdate_requests WHERE id=? AND to_user_id=?",
            (req_id, uid)
        ).fetchone()
        if not req:
            raise HTTPException(404, "Anfrage nicht gefunden.")
        if req["status"] != "pending":
            raise HTTPException(409, "Anfrage wurde bereits beantwortet.")

        conn.execute(
            "UPDATE playdate_requests SET status=? WHERE id=?",
            (data.status, req_id)
        )

        conv_id = None
        if data.status == "accepted":
            conv_id = _ensure_conversation(conn, uid, req["from_user_id"])

    try:
        from routes.push import send_push_to_user
        verb = "angenommen" if data.status == "accepted" else "abgelehnt"
        send_push_to_user(req["from_user_id"], {
            "title": f"Playdate {verb}!",
            "body":  f"{user['name']} hat deine Anfrage {verb}.",
            "type":  "playdate_response",
            "tag":   f"playdate-{req_id}",
            "data":  {"page": "playdate"},
        })
    except Exception:
        pass

    return {"ok": True, "conversation_id": conv_id}
