"""
POI Context API Endpoints

REST API for POI detection, retrieval, and management.
"""

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Optional
import structlog
import uuid

from app.core.database import get_db
from app.services.poi_detection_service import POIDetectionService
from app.services.poi_feature_selector import POIFeatureSelector
from app.services.competitor_analyzer import CompetitorAnalyzer
from app.services.poi_refresh_service import POIRefreshService
from app.repositories.poi_context_repository import POIContextRepository
from app.cache.poi_cache_service import POICacheService
from app.core.redis_client import get_redis_client
from shared.routing.route_builder import RouteBuilder

logger = structlog.get_logger()

route_builder = RouteBuilder('external')
router = APIRouter(tags=["POI Context"])


@router.post(
    route_builder.build_base_route("poi-context/detect")
)
async def detect_pois_for_tenant(
    tenant_id: str,
    latitude: float = Query(..., description="Bakery latitude"),
    longitude: float = Query(..., description="Bakery longitude"),
    force_refresh: bool = Query(False, description="Force refresh, skip cache"),
    db: AsyncSession = Depends(get_db)
):
    """
    Detect POIs for a tenant's bakery location.

    Performs automated POI detection using Overpass API, calculates ML features,
    and stores results for demand forecasting.
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    logger.info(
        "POI detection requested",
        tenant_id=tenant_id,
        location=(latitude, longitude),
        force_refresh=force_refresh
    )

    try:
        # Initialize services
        poi_service = POIDetectionService()
        feature_selector = POIFeatureSelector()
        competitor_analyzer = CompetitorAnalyzer()
        poi_repo = POIContextRepository(db)
        redis_client = await get_redis_client()
        cache_service = POICacheService(redis_client)

        # Check cache first (unless force refresh)
        if not force_refresh:
            cached_result = await cache_service.get_cached_pois(latitude, longitude)
            if cached_result:
                logger.info("Using cached POI results", tenant_id=tenant_id)
                # Still save to database for this tenant
                poi_context = await poi_repo.create_or_update(tenant_uuid, cached_result)
                return {
                    "status": "success",
                    "source": "cache",
                    "poi_context": poi_context.to_dict()
                }

        # Detect POIs
        poi_results = await poi_service.detect_pois_for_bakery(
            latitude, longitude, tenant_id
        )

        # Select relevant features
        try:
            feature_selection = feature_selector.select_relevant_features(
                poi_results["poi_categories"],
                tenant_id
            )
        except Exception as e:
            logger.error(
                "Feature selection failed", 
                tenant_id=tenant_id, 
                error=str(e),
                exc_info=True
            )
            # Provide default feature selection to continue
            feature_selection = {
                "features": {},
                "relevant_categories": [],
                "relevance_report": [],
                "total_features": 0,
                "total_relevant_categories": 0
            }

        # Analyze competitors specifically
        try:
            competitors_data = poi_results["poi_categories"].get("competitors", {})
            competitor_pois = competitors_data.get("pois", [])
            competitor_analysis = competitor_analyzer.analyze_competitive_landscape(
                competitor_pois,
                (latitude, longitude),
                tenant_id
            )
        except Exception as e:
            logger.error(
                "Competitor analysis failed", 
                tenant_id=tenant_id, 
                error=str(e),
                exc_info=True
            )
            # Provide default competitor analysis to continue
            competitor_analysis = {
                "competitive_pressure_score": 0.0,
                "direct_competitors_count": 0,
                "nearby_competitors_count": 0,
                "market_competitors_count": 0,
                "total_competitors_count": 0,
                "competitive_zone": "low_competition",
                "market_type": "underserved",
                "competitive_advantage": "first_mover",
                "ml_feature_competitive_pressure": 0.0,
                "ml_feature_has_direct_competitor": 0,
                "ml_feature_competitor_density_500m": 0,
                "competitor_details": [],
                "nearest_competitor": None
            }

        # Generate competitive insights
        try:
            competitive_insights = competitor_analyzer.get_competitive_insights(
                competitor_analysis
            )
        except Exception as e:
            logger.warning(
                "Failed to generate competitive insights", 
                tenant_id=tenant_id, 
                error=str(e)
            )
            competitive_insights = []

        # Combine results
        enhanced_results = {
            **poi_results,
            "ml_features": feature_selection.get("features", {}),
            "relevant_categories": feature_selection.get("relevant_categories", []),
            "relevance_report": feature_selection.get("relevance_report", []),
            "competitor_analysis": competitor_analysis,
            "competitive_insights": competitive_insights
        }

        # Cache results
        try:
            await cache_service.cache_poi_results(latitude, longitude, enhanced_results)
        except Exception as e:
            logger.warning(
                "Failed to cache POI results", 
                tenant_id=tenant_id, 
                error=str(e)
            )

        # Save to database
        try:
            poi_context = await poi_repo.create_or_update(tenant_uuid, enhanced_results)
        except Exception as e:
            logger.error(
                "Failed to save POI context to database", 
                tenant_id=tenant_id, 
                error=str(e),
                exc_info=True
            )
            raise HTTPException(
                status_code=500,
                detail=f"Failed to save POI context: {str(e)}"
            )

        # Schedule automatic refresh job (180 days from now)
        try:
            poi_refresh_service = POIRefreshService()
            refresh_job = await poi_refresh_service.schedule_refresh_job(
                tenant_id=tenant_id,
                latitude=latitude,
                longitude=longitude,
                session=db
            )
            logger.info(
                "POI refresh job scheduled",
                tenant_id=tenant_id,
                job_id=str(refresh_job.id),
                scheduled_at=refresh_job.scheduled_at
            )
        except Exception as e:
            logger.warning(
                "Failed to schedule POI refresh job",
                tenant_id=tenant_id,
                error=str(e)
            )

        logger.info(
            "POI detection completed",
            tenant_id=tenant_id,
            total_pois=poi_context.total_pois_detected,
            relevant_categories=len(feature_selection.get("relevant_categories", []))
        )

        # Phase 3: Auto-trigger calendar suggestion after POI detection
        # This helps admins by providing intelligent calendar recommendations
        calendar_suggestion = None
        try:
            from app.utils.calendar_suggester import CalendarSuggester
            from app.repositories.calendar_repository import CalendarRepository

            # Get tenant's location context
            calendar_repo = CalendarRepository(db)
            location_context = await calendar_repo.get_tenant_location_context(tenant_uuid)

            if location_context and location_context.school_calendar_id is None:
                # Only suggest if no calendar assigned yet
                city_id = location_context.city_id

                # Get available calendars for city
                calendars_result = await calendar_repo.get_calendars_by_city(city_id, enabled_only=True)
                calendars = calendars_result.get("calendars", []) if calendars_result else []

                if calendars:
                    # Generate suggestion using POI data
                    suggester = CalendarSuggester()
                    calendar_suggestion = suggester.suggest_calendar_for_tenant(
                        city_id=city_id,
                        available_calendars=calendars,
                        poi_context=poi_context.to_dict(),
                        tenant_data=None
                    )

                    logger.info(
                        "Calendar suggestion auto-generated after POI detection",
                        tenant_id=tenant_id,
                        suggested_calendar=calendar_suggestion.get("calendar_name"),
                        confidence=calendar_suggestion.get("confidence_percentage"),
                        should_auto_assign=calendar_suggestion.get("should_auto_assign")
                    )

                    # TODO: Send notification to admin about available suggestion
                    # This will be implemented when notification service is integrated
                else:
                    logger.info(
                        "No calendars available for city, skipping suggestion",
                        tenant_id=tenant_id,
                        city_id=city_id
                    )
            elif location_context and location_context.school_calendar_id:
                logger.info(
                    "Calendar already assigned, skipping suggestion",
                    tenant_id=tenant_id,
                    calendar_id=str(location_context.school_calendar_id)
                )
            else:
                logger.warning(
                    "No location context found, skipping calendar suggestion",
                    tenant_id=tenant_id
                )

        except Exception as e:
            # Non-blocking: POI detection should succeed even if suggestion fails
            logger.warning(
                "Failed to auto-generate calendar suggestion (non-blocking)",
                tenant_id=tenant_id,
                error=str(e)
            )

        return {
            "status": "success",
            "source": "detection",
            "poi_context": poi_context.to_dict(),
            "feature_selection": feature_selection,
            "competitor_analysis": competitor_analysis,
            "competitive_insights": competitive_insights,
            "calendar_suggestion": calendar_suggestion  # Include suggestion in response
        }

    except Exception as e:
        logger.error(
            "POI detection failed",
            tenant_id=tenant_id,
            error=str(e),
            exc_info=True
        )
        raise HTTPException(
            status_code=500,
            detail=f"POI detection failed: {str(e)}"
        )


@router.get(
    route_builder.build_base_route("poi-context")
)
async def get_poi_context(
    tenant_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    Get POI context for a tenant.

    Returns stored POI detection results and ML features.
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    poi_repo = POIContextRepository(db)
    poi_context = await poi_repo.get_by_tenant_id(tenant_uuid)

    if not poi_context:
        raise HTTPException(
            status_code=404,
            detail=f"POI context not found for tenant {tenant_id}"
        )

    # Check if stale
    is_stale = poi_context.is_stale()

    return {
        "poi_context": poi_context.to_dict(),
        "is_stale": is_stale,
        "needs_refresh": is_stale
    }


@router.post(
    route_builder.build_base_route("poi-context/refresh")
)
async def refresh_poi_context(
    tenant_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    Refresh POI context for a tenant.

    Re-detects POIs and updates stored data.
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    poi_repo = POIContextRepository(db)
    existing_context = await poi_repo.get_by_tenant_id(tenant_uuid)

    if not existing_context:
        raise HTTPException(
            status_code=404,
            detail=f"POI context not found for tenant {tenant_id}. Use detect endpoint first."
        )

    # Perform detection with force_refresh=True
    return await detect_pois_for_tenant(
        tenant_id=tenant_id,
        latitude=existing_context.latitude,
        longitude=existing_context.longitude,
        force_refresh=True,
        db=db
    )


@router.delete(
    route_builder.build_base_route("poi-context")
)
async def delete_poi_context(
    tenant_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    Delete POI context for a tenant.
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    poi_repo = POIContextRepository(db)
    deleted = await poi_repo.delete_by_tenant_id(tenant_uuid)

    if not deleted:
        raise HTTPException(
            status_code=404,
            detail=f"POI context not found for tenant {tenant_id}"
        )

    return {
        "status": "success",
        "message": f"POI context deleted for tenant {tenant_id}"
    }


@router.get(
    route_builder.build_base_route("poi-context/feature-importance")
)
async def get_feature_importance(
    tenant_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    Get feature importance summary for tenant's POI context.

    Shows which POI categories are relevant and their impact scores.
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    poi_repo = POIContextRepository(db)
    poi_context = await poi_repo.get_by_tenant_id(tenant_uuid)

    if not poi_context:
        raise HTTPException(
            status_code=404,
            detail=f"POI context not found for tenant {tenant_id}"
        )

    feature_selector = POIFeatureSelector()
    importance_summary = feature_selector.get_feature_importance_summary(
        poi_context.poi_detection_results
    )

    return {
        "tenant_id": tenant_id,
        "feature_importance": importance_summary,
        "total_categories": len(importance_summary),
        "relevant_categories": sum(1 for cat in importance_summary if cat["is_relevant"])
    }


@router.get(
    route_builder.build_base_route("poi-context/competitor-analysis")
)
async def get_competitor_analysis(
    tenant_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    Get detailed competitor analysis for tenant location.
    """
    try:
        tenant_uuid = uuid.UUID(tenant_id)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid tenant_id format")

    poi_repo = POIContextRepository(db)
    poi_context = await poi_repo.get_by_tenant_id(tenant_uuid)

    if not poi_context:
        raise HTTPException(
            status_code=404,
            detail=f"POI context not found for tenant {tenant_id}"
        )

    competitor_analyzer = CompetitorAnalyzer()
    competitors = poi_context.poi_detection_results.get("competitors", {}).get("pois", [])

    analysis = competitor_analyzer.analyze_competitive_landscape(
        competitors,
        (poi_context.latitude, poi_context.longitude),
        tenant_id
    )

    insights = competitor_analyzer.get_competitive_insights(analysis)

    return {
        "tenant_id": tenant_id,
        "location": {
            "latitude": poi_context.latitude,
            "longitude": poi_context.longitude
        },
        "competitor_analysis": analysis,
        "insights": insights
    }


@router.get("/health")
async def poi_health_check():
    """
    Check POI detection service health.

    Verifies Overpass API accessibility.
    """
    poi_service = POIDetectionService()
    health = await poi_service.health_check()

    if not health["healthy"]:
        raise HTTPException(
            status_code=503,
            detail=f"POI detection service unhealthy: {health.get('error', 'Unknown error')}"
        )

    return {
        "status": "healthy",
        "overpass_api": health
    }


@router.get("/cache/stats")
async def get_cache_stats():
    """
    Get POI cache statistics.
    """
    try:
        redis_client = await get_redis_client()
        cache_service = POICacheService(redis_client)
        stats = await cache_service.get_cache_stats()

        return {
            "status": "success",
            "cache_stats": stats
        }
    except Exception as e:
        logger.error("Failed to get cache stats", error=str(e))
        raise HTTPException(
            status_code=500,
            detail=f"Failed to get cache stats: {str(e)}"
        )
