from fastapi import FastAPI, Depends, HTTPException, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from typing import List, Dict
import json
from datetime import datetime

from .database import engine, get_db, Base
from . import models, schemas

# Create tables
Base.metadata.create_all(bind=engine)

app = FastAPI(title="LinksMatch API", version="1.0.0")

# CORS - allow frontend from any origin for local development
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# WebSocket connection manager for real-time messaging
class ConnectionManager:
    def __init__(self):
        self.active_connections: Dict[int, WebSocket] = {}

    async def connect(self, user_id: int, websocket: WebSocket):
        await websocket.accept()
        self.active_connections[user_id] = websocket
        print(f"User {user_id} connected. Total: {len(self.active_connections)}")

    def disconnect(self, user_id: int):
        if user_id in self.active_connections:
            del self.active_connections[user_id]
            print(f"User {user_id} disconnected")

    async def send_personal_message(self, message: dict, receiver_id: int):
        if receiver_id in self.active_connections:
            await self.active_connections[receiver_id].send_text(json.dumps(message))

manager = ConnectionManager()

# ------------------------------
# Seed data on startup
# ------------------------------
def seed_data(db: Session):
    if db.query(models.User).count() > 0:
        return  # Already seeded

    users = [
        models.User(id=1, name="Alex Rivera", email="alex@links.com", handicap=4.2, bio="Pebble Beach Member. Love early morning rounds.", avatar_url="https://picsum.photos/id/1005/200/200", location="Pebble Beach, CA", rounds_played=142, match_rating=4.98),
        models.User(id=2, name="Morgan Ellis", email="morgan@links.com", handicap=6.8, bio="Travel for work, play 35+ rounds/year at top courses.", avatar_url="https://picsum.photos/id/1011/200/200", location="San Francisco, CA", rounds_played=87, match_rating=4.85),
        models.User(id=3, name="Jordan Hale", email="jordan@links.com", handicap=2.1, bio="Competitive player. Always looking for serious partners.", avatar_url="https://picsum.photos/id/1009/200/200", location="New York, NY", rounds_played=210, match_rating=4.92),
        models.User(id=4, name="Taylor Quinn", email="taylor@links.com", handicap=9.4, bio="Play mostly on the weekends at private clubs.", avatar_url="https://picsum.photos/id/1012/200/200", location="Los Angeles, CA", rounds_played=61, match_rating=4.71),
        models.User(id=5, name="Sam Brooks", email="sam@links.com", handicap=5.9, bio="St Andrews member. Frequent traveler.", avatar_url="https://picsum.photos/id/64/200/200", location="Boston, MA", rounds_played=119, match_rating=4.88),
    ]

    courses = [
        models.Course(id=1, name="Pebble Beach Golf Links", location="Pebble Beach, CA", description="World #1. Stunning ocean views.", image_url="https://picsum.photos/id/1016/800/500", partners_seeking=47, rating=4.98),
        models.Course(id=2, name="Bandon Dunes - Pacific Dunes", location="Bandon, OR", description="Pure links golf on the Oregon coast.", image_url="https://picsum.photos/id/1033/800/500", partners_seeking=29, rating=4.95),
        models.Course(id=3, name="Shinnecock Hills Golf Club", location="Southampton, NY", description="Classic private club.", image_url="https://picsum.photos/id/160/800/500", partners_seeking=18, rating=4.97),
    ]

    for user in users:
        db.add(user)
    for course in courses:
        db.add(course)

    db.commit()
    print("✅ LinksMatch seed data loaded (5 users + 3 courses)")

@app.on_event("startup")
def startup_event():
    db = next(get_db())
    seed_data(db)

# ------------------------------
# REST API Endpoints
# ------------------------------

@app.get("/")
def root():
    return {"message": "LinksMatch API is running", "docs": "/docs"}

@app.get("/users", response_model=List[schemas.User])
def get_users(db: Session = Depends(get_db)):
    return db.query(models.User).all()

@app.get("/users/{user_id}", response_model=schemas.User)
def get_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(models.User).filter(models.User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

@app.get("/courses", response_model=List[schemas.Course])
def get_courses(db: Session = Depends(get_db)):
    return db.query(models.Course).all()

@app.get("/matches", response_model=List[schemas.Match])
def get_matches(user_id: int, db: Session = Depends(get_db)):
    return db.query(models.Match).filter(
        (models.Match.user_id == user_id) | (models.Match.partner_id == user_id)
    ).all()

@app.post("/matches", response_model=schemas.Match)
def create_match(match: schemas.MatchCreate, user_id: int = 1, db: Session = Depends(get_db)):
    """Create a match request (defaults to current user = 1 for demo)"""
    new_match = models.Match(
        user_id=user_id,
        partner_id=match.partner_id,
        course_id=match.course_id,
        preferred_date=match.preferred_date,
        status="pending"
    )
    db.add(new_match)
    db.commit()
    db.refresh(new_match)
    return new_match

@app.post("/matches/{match_id}/confirm")
def confirm_match(match_id: int, db: Session = Depends(get_db)):
    match = db.query(models.Match).filter(models.Match.id == match_id).first()
    if not match:
        raise HTTPException(status_code=404, detail="Match not found")
    match.status = "confirmed"
    db.commit()
    return {"status": "confirmed", "match_id": match_id}

# Messaging REST endpoints
@app.get("/messages/{other_user_id}", response_model=List[schemas.Message])
def get_messages(other_user_id: int, user_id: int = 1, db: Session = Depends(get_db)):
    messages = db.query(models.Message).filter(
        ((models.Message.sender_id == user_id) & (models.Message.receiver_id == other_user_id)) |
        ((models.Message.sender_id == other_user_id) & (models.Message.receiver_id == user_id))
    ).order_by(models.Message.created_at.asc()).all()
    return messages

@app.post("/messages", response_model=schemas.Message)
async def send_message(msg: schemas.MessageCreate, user_id: int = 1, db: Session = Depends(get_db)):
    new_msg = models.Message(
        sender_id=user_id,
        receiver_id=msg.receiver_id,
        content=msg.content
    )
    db.add(new_msg)
    db.commit()
    db.refresh(new_msg)

    # Broadcast via websocket if receiver is connected
    message_payload = {
        "type": "new_message",
        "id": new_msg.id,
        "sender_id": new_msg.sender_id,
        "receiver_id": new_msg.receiver_id,
        "content": new_msg.content,
        "created_at": new_msg.created_at.isoformat(),
    }
    await manager.send_personal_message(message_payload, msg.receiver_id)
    return new_msg

# ------------------------------
# Real-time WebSocket Messaging
# ------------------------------
@app.websocket("/ws/{user_id}")
async def websocket_endpoint(websocket: WebSocket, user_id: int):
    await manager.connect(user_id, websocket)
    try:
        while True:
            data = await websocket.receive_text()
            # Expect JSON: {"receiver_id": 2, "content": "Hey, want to play?"}
            try:
                payload = json.loads(data)
                receiver_id = payload.get("receiver_id")
                content = payload.get("content", "")

                if receiver_id and content:
                    # Save to DB
                    db = next(get_db())
                    new_msg = models.Message(
                        sender_id=user_id,
                        receiver_id=receiver_id,
                        content=content
                    )
                    db.add(new_msg)
                    db.commit()
                    db.refresh(new_msg)

                    # Send to receiver
                    message_payload = {
                        "type": "new_message",
                        "id": new_msg.id,
                        "sender_id": user_id,
                        "receiver_id": receiver_id,
                        "content": content,
                        "created_at": new_msg.created_at.isoformat(),
                    }
                    await manager.send_personal_message(message_payload, receiver_id)

                    # Echo back to sender (for immediate UI update)
                    await websocket.send_text(json.dumps(message_payload))
            except Exception as e:
                await websocket.send_text(json.dumps({"error": str(e)}))
    except WebSocketDisconnect:
        manager.disconnect(user_id)

# Simple health check
@app.get("/health")
def health():
    return {"status": "healthy", "connections": len(manager.active_connections)}