# app/routers/visitors.py

import uuid
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy.orm import aliased
from app.schemas.page_view import *
from app.models.client import Client
from app.core.database import get_db
from app.models.visitor import Visitor
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import func, select, literal_column
from app.schemas.visitor import VisitorCreate, VisitorOut, ClientVisitor
from fastapi import APIRouter, Depends, HTTPException, Request ,Query
from app.models.page_view import VisitorPageView,VisitorActivity
from app.services.visitor import create_or_get_visitor, get_visitor_by_visitor_id

router = APIRouter(prefix="/visitors", tags=["Visitors"])

print(" ---------------- in visitor ---------------- ")


# -----------------------------------------------------
# Create a visitor OR return existing one
# -----------------------------------------------------
@router.post("/", response_model=VisitorOut)
async def add_visitor(data: VisitorCreate, db: Session = Depends(get_db)):
    """
    If visitor exists (same visitor_id + client_id), return it.
    If not, create new visitor.
    """
    print("><><><><><><><><>",data)
    return await create_or_get_visitor(db, data)


# -----------------------------------------------------
# Used by WebSocket: Validate visitor before connecting
# -----------------------------------------------------
@router.get("/{visitor_id}", response_model=VisitorOut)
async def get_visitor(visitor_id: str, db: Session = Depends(get_db)):
    """
    Admin & Visitor WebSocket checks if visitor exists
    before allowing the session.
    """
    visitor = await get_visitor_by_visitor_id(db, visitor_id)
    if not visitor:
        raise HTTPException(status_code=404, detail="Visitor not found")

    return visitor


# -------------------------------------------
# AUTO CREATE FOR VISITOR WITH APPROPRIATE ID
# -------------------------------------------
@router.post("/auto-create")
async def auto_create_visitor(request: Request, db: AsyncSession = Depends(get_db)):
    body = await request.json()

    client_widget_id = body.get("client_widget_id")

    client_Data = await db.execute(
            select(Client).where(Client.client_widget_id == client_widget_id)
    )

    client_Data = client_Data.scalar_one_or_none()

    # generate random visitor id
    visitor_uid = str(uuid.uuid4())[:8]
    
    # Comes directly from the HTTP request
    ip_address = request.client.host

    user_agent = request.headers.get("user-agent", "")

    # OPTIONAL: third-party or geoip lookup
    country = body.get("country")
    region = body.get("region")
    city = body.get("city")
    
    # ip_address = body.get("ip_address")

    visitor = Visitor(
        client_id=client_Data.id,
        visitor_id=visitor_uid,
        ip_address=ip_address,
        country=country,
        region=region,
        city=city,
        name=None,
    )

    db.add(visitor)
    await db.commit()

    return {"visitor_id": visitor_uid}


@router.post("/page-view")
async def page_view(data: PageViewSchema, db: Session = Depends(get_db)):
    
    new_view = VisitorPageView(
        visitor_id=data.visitor_id,
        client_widget_id=data.client_widget_id,
        page_url=data.page_url,
        page_title=data.page_title,
    )

    db.add(new_view)
    await db.commit()

    return {"status": "success", "message": "Page view recorded"}


# -------------------------------
# LIVE ACTIVITY PING
# -------------------------------
@router.post("/live-activity")
async def live_activity(data: ActivityPingSchema, db: AsyncSession = Depends(get_db)):

    # Get existing activity row
    result = await db.execute(
        select(VisitorActivity).where(VisitorActivity.visitor_id == data.visitor_id)
    )
    activity = result.scalars().first()

    if activity:
        # Update existing
        activity.current_page = data.page_url
        activity.last_active = datetime.utcnow()
        activity.timestamp = data.timestamp

    else:
        # Create new row
        activity = VisitorActivity(
            visitor_id=data.visitor_id,
            current_page=data.page_url,
            timestamp=data.timestamp,
            last_active=datetime.utcnow(),
        )
        db.add(activity)

    await db.commit()

    return {"status": "success", "message": "Activity updated"}


# ---------------------------------
# VISITOR STATISTICS
# ---------------------------------
@router.get("/stats/visitor-stats")
async def visitor_stats(
    client_widget_id: str,      # REQUIRED FILTER
    db: AsyncSession = Depends(get_db)
):

    ClientAlias = aliased(Client)

    # DAILY
    daily_stmt = (
        select(
            ClientAlias.client_widget_id,
            ClientAlias.client_name,
            ClientAlias.website_url,
            func.date_format(Visitor.created_at, "%Y-%m-%d").label("period"),
            func.count(Visitor.id).label("visitor_count"),
            literal_column("'day'").label("period_type")
        )
        .join(ClientAlias, Visitor.client_id == ClientAlias.id)
        .where(ClientAlias.client_widget_id == client_widget_id)   # <--- FILTER HERE
        .group_by(ClientAlias.client_widget_id, func.date_format(Visitor.created_at, "%Y-%m-%d"))
    )

    # WEEKLY
    weekly_stmt = (
        select(
            ClientAlias.client_widget_id,
            ClientAlias.client_name,
            ClientAlias.website_url,
            func.yearweek(Visitor.created_at).label("period"),
            func.count(Visitor.id).label("visitor_count"),
            literal_column("'week'").label("period_type")
        )
        .join(ClientAlias, Visitor.client_id == ClientAlias.id)
        .where(ClientAlias.client_widget_id == client_widget_id)   # <--- FILTER
        .group_by(ClientAlias.client_widget_id, func.yearweek(Visitor.created_at))
    )

    # MONTHLY
    monthly_stmt = (
        select(
            ClientAlias.client_widget_id,
            ClientAlias.client_name,
            ClientAlias.website_url,
            func.date_format(Visitor.created_at, "%Y-%m").label("period"),
            func.count(Visitor.id).label("visitor_count"),
            literal_column("'month'").label("period_type")
        )
        .join(ClientAlias, Visitor.client_id == ClientAlias.id)
        .where(ClientAlias.client_widget_id == client_widget_id)   # <--- FILTER
        .group_by(ClientAlias.client_widget_id, func.date_format(Visitor.created_at, "%Y-%m"))
    )

    # YEARLY
    yearly_stmt = (
        select(
            ClientAlias.client_widget_id,
            ClientAlias.client_name,
            ClientAlias.website_url,
            func.date_format(Visitor.created_at, "%Y").label("period"),
            func.count(Visitor.id).label("visitor_count"),
            literal_column("'year'").label("period_type")
        )
        .join(ClientAlias, Visitor.client_id == ClientAlias.id)
        .where(ClientAlias.client_widget_id == client_widget_id)   # <--- FILTER
        .group_by(ClientAlias.client_widget_id, func.date_format(Visitor.created_at, "%Y"))
    )

    # OVERALL
    overall_stmt = (
        select(
            ClientAlias.client_widget_id,
            ClientAlias.client_name,
            ClientAlias.website_url,
            literal_column("'overall'").label("period"),
            func.count(Visitor.id).label("visitor_count"),
            literal_column("'overall'").label("period_type")
        )
        .join(ClientAlias, Visitor.client_id == ClientAlias.id)
        .where(ClientAlias.client_widget_id == client_widget_id)   # <--- FILTER
        .group_by(ClientAlias.client_widget_id)
    )

    # UNION ALL
    union_stmt = daily_stmt.union_all(
        weekly_stmt,
        monthly_stmt,
        yearly_stmt,
        overall_stmt
    )

    result = await db.execute(union_stmt)
    rows = result.all()

    # FORMAT RESPONSE
    data = {}

    for client_widget_id, client_name, website_url, period, visitor_count, period_type in rows:

        if client_widget_id not in data:
            data[client_widget_id] = {
                "client_name": client_name,
                "website_url": website_url,
                "daily_stats": [],
                "weekly_stats": [],
                "monthly_stats": [],
                "yearly_stats": [],
                "overall_visitors": 0,
            }

        if period_type == "day":
            data[client_widget_id]["daily_stats"].append({
                "day": period,
                "total_visitors": visitor_count
            })

        elif period_type == "week":
            data[client_widget_id]["weekly_stats"].append({
                "week": period,
                "total_visitors": visitor_count
            })

        elif period_type == "month":
            data[client_widget_id]["monthly_stats"].append({
                "month": period,
                "total_visitors": visitor_count
            })

        elif period_type == "year":
            data[client_widget_id]["yearly_stats"].append({
                "year": period,
                "total_visitors": visitor_count
            })

        elif period_type == "overall":
            data[client_widget_id]["overall_visitors"] = visitor_count

    return {"stats": data}


# --------------------------------
# PERTICULAR CLIENT'S VISITORS
# --------------------------------

@router.get("/clients/{client_id}/visitors")
async def get_visitors_by_client(
    client_id: int,
    db: AsyncSession = Depends(get_db),
    limit: int = Query(10, ge=1),
    offset: int = Query(0, ge=0)
):
    
    # Query: Paginated Visitors
    stmt = (
        select(Visitor)
        .where(Visitor.client_id == client_id)
        .order_by(Visitor.created_at.desc())
        .limit(limit)
        .offset(offset)
    )

    result = await db.execute(stmt)
    visitors = result.scalars().all()

    # Query: Total Count
    count_stmt = (
        select(func.count())
        .select_from(Visitor)
        .where(Visitor.client_id == client_id)
    )

    total = (await db.execute(count_stmt)).scalar()

    return {
        "visitors": visitors,
        "total": total
    }



# --------------------------------
# Get Visitor Live Activity
# --------------------------------
@router.get("/live-page/views")
async def get_visitor_page_views(
    visitor_id: str,
    db: AsyncSession = Depends(get_db),
    limit: int = Query(10, ge=1),       # pagination limit
    offset: int = Query(0, ge=0)        # pagination offset
):
    """
    Returns paginated page-view activity timeline for a visitor
    """

    # -------------------------------
    # 1) Fetch paginated results
    # -------------------------------
    stmt = (
        select(VisitorPageView)
        .where(VisitorPageView.visitor_id == visitor_id)
        .order_by(VisitorPageView.created_at.desc())
        .limit(limit)
        .offset(offset)
    )

    result = await db.execute(stmt)
    rows = result.scalars().all()

    # -------------------------------
    # 2) Get TOTAL count (no limit)
    # -------------------------------
    count_stmt = (
        select(func.count())
        .select_from(VisitorPageView)
        .where(VisitorPageView.visitor_id == visitor_id)
    )

    total_views = (await db.execute(count_stmt)).scalar()

    # Format page views
    page_views = [
        {
            "id": r.id,
            "visitor_id": r.visitor_id,
            "client_widget_id": r.client_widget_id,
            "page_url": r.page_url,
            "page_title": r.page_title,
            "created_at": r.created_at,
        }
        for r in rows
    ]

    return {
        "visitor_id": visitor_id,
        "total_views": total_views,
        "limit": limit,
        "offset": offset,
        "page": (offset // limit) + 1,
        "page_views": page_views
    }
