"""BAN YARO — Hundefreundliche Orte"""

import math
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()

TYPEN = {'restaurant', 'shop', 'freilauf', 'kotbeutel', 'tierarzt', 'hundeschule'}


def _haversine(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
    R  = 6_371_000
    p1 = math.radians(lat1)
    p2 = math.radians(lat2)
    dp = math.radians(lat2 - lat1)
    dl = math.radians(lon2 - lon1)
    a  = math.sin(dp / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
    return 2 * R * math.asin(math.sqrt(a))


# ------------------------------------------------------------------
# Schemas
# ------------------------------------------------------------------
class PlaceCreate(BaseModel):
    name:              str
    typ:               str
    lat:               float
    lon:               float
    adresse:           Optional[str]  = None
    website:           Optional[str]  = None
    telefon:           Optional[str]  = None
    hund_rein:         Optional[bool] = None
    leine_pflicht:     Optional[bool] = None
    wasser_fuer_hunde: Optional[bool] = None

class PlaceUpdate(BaseModel):
    name:              Optional[str]  = None
    typ:               Optional[str]  = None
    lat:               Optional[float]= None
    lon:               Optional[float]= None
    adresse:           Optional[str]  = None
    website:           Optional[str]  = None
    telefon:           Optional[str]  = None
    hund_rein:         Optional[bool] = None
    leine_pflicht:     Optional[bool] = None
    wasser_fuer_hunde: Optional[bool] = None


def _row_to_dict(row) -> dict:
    d = dict(row)
    for k in ('hund_rein', 'leine_pflicht', 'wasser_fuer_hunde'):
        if d.get(k) is not None:
            d[k] = bool(d[k])
    return d


# ------------------------------------------------------------------
# GET /api/places — alle Orte (optional: Umkreis + Typ-Filter)
# ------------------------------------------------------------------
@router.get("")
async def list_places(
    lat:    Optional[float] = None,
    lon:    Optional[float] = None,
    radius: int             = 5000,
    typ:    Optional[str]   = None,
):
    with db() as conn:
        q      = "SELECT p.*, u.name AS user_name FROM places p LEFT JOIN users u ON u.id = p.user_id"
        params = []
        if typ:
            q += " WHERE p.typ = ?"
            params.append(typ)
        q += " ORDER BY p.created_at DESC"
        rows = conn.execute(q, params).fetchall()

    result = [_row_to_dict(r) for r in rows]
    if lat is not None and lon is not None:
        result = [r for r in result if _haversine(lat, lon, r['lat'], r['lon']) <= radius]
    return result


# ------------------------------------------------------------------
# POST /api/places — neuen Ort anlegen (Login erforderlich)
# ------------------------------------------------------------------
@router.post("", status_code=201)
async def create_place(data: PlaceCreate, user=Depends(get_current_user)):
    if data.typ not in TYPEN:
        raise HTTPException(400, f"Ungültiger Typ. Erlaubt: {', '.join(sorted(TYPEN))}")
    with db() as conn:
        cur = conn.execute("""
            INSERT INTO places
                (user_id, name, typ, lat, lon, adresse, website, telefon,
                 hund_rein, leine_pflicht, wasser_fuer_hunde)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            user['id'], data.name, data.typ, data.lat, data.lon,
            data.adresse, data.website, data.telefon,
            int(data.hund_rein)         if data.hund_rein         is not None else None,
            int(data.leine_pflicht)     if data.leine_pflicht     is not None else None,
            int(data.wasser_fuer_hunde) if data.wasser_fuer_hunde is not None else None,
        ))
        row = conn.execute(
            "SELECT p.*, u.name AS user_name FROM places p LEFT JOIN users u ON u.id = p.user_id WHERE p.id = ?",
            (cur.lastrowid,)
        ).fetchone()
    return _row_to_dict(row)


# ------------------------------------------------------------------
# GET /api/places/{id}
# ------------------------------------------------------------------
@router.get("/{place_id}")
async def get_place(place_id: int):
    with db() as conn:
        row = conn.execute(
            "SELECT p.*, u.name AS user_name FROM places p LEFT JOIN users u ON u.id = p.user_id WHERE p.id = ?",
            (place_id,)
        ).fetchone()
    if not row:
        raise HTTPException(404, "Ort nicht gefunden.")
    return _row_to_dict(row)


# ------------------------------------------------------------------
# PATCH /api/places/{id} — bearbeiten (nur eigene)
# ------------------------------------------------------------------
@router.patch("/{place_id}")
async def update_place(place_id: int, data: PlaceUpdate, user=Depends(get_current_user)):
    with db() as conn:
        row = conn.execute("SELECT * FROM places WHERE id = ?", (place_id,)).fetchone()
        if not row:
            raise HTTPException(404, "Ort nicht gefunden.")
        if row['user_id'] != user['id']:
            raise HTTPException(403, "Nicht berechtigt.")

        updates = data.model_dump(exclude_none=True)
        if not updates:
            return _row_to_dict(row)

        for key in ('hund_rein', 'leine_pflicht', 'wasser_fuer_hunde'):
            if key in updates:
                updates[key] = int(updates[key])

        cols = ', '.join(f"{k} = ?" for k in updates)
        conn.execute(f"UPDATE places SET {cols} WHERE id = ?", [*updates.values(), place_id])
        row = conn.execute(
            "SELECT p.*, u.name AS user_name FROM places p LEFT JOIN users u ON u.id = p.user_id WHERE p.id = ?",
            (place_id,)
        ).fetchone()
    return _row_to_dict(row)


# ------------------------------------------------------------------
# DELETE /api/places/{id}
# ------------------------------------------------------------------
@router.delete("/{place_id}", status_code=204)
async def delete_place(place_id: int, user=Depends(get_current_user)):
    with db() as conn:
        row = conn.execute("SELECT * FROM places WHERE id = ?", (place_id,)).fetchone()
        if not row:
            raise HTTPException(404, "Ort nicht gefunden.")
        if row['user_id'] != user['id']:
            raise HTTPException(403, "Nicht berechtigt.")
        conn.execute("DELETE FROM places WHERE id = ?", (place_id,))
