import json
import logging
import math
import traceback
from typing import Optional, Dict, Any, List

from fastapi import APIRouter, Depends, Request
from pydantic import BaseModel, ValidationError
from sqlalchemy import and_, or_, select, func
from sqlalchemy.ext.asyncio import AsyncSession

from app.db.session import get_db
from app.models.category import Category
from app.models.generated_tattoo_history import GeneratedTattooHistory
from app.core.security import validate_token
from app.api.v1.crypto_api import decrypt_data
from app.utils.responses import custom_response
from app.core.logging import logger
from app.models.tattoo_style import TattooStyle
from app.models.category import Category
router = APIRouter()

# ---------- Get Dashboard Data (GET with query params and Bearer Token) ----------
@router.get("/dashboard")
async def get_dashboard_data(
    request: Request,
    db: AsyncSession = Depends(get_db),
    token_data: dict = Depends(validate_token)
):
    """
    Get dashboard data (categories and optionally user history) based on the token.
    Uses default pagination and extracts user info from the token.
    """
    logger.info("Received request for /dashboard endpoint.")
    try:
        # Step 1: Authorization check
        if token_data.get('code') != 200:
            logger.warning(f"Unauthorized access attempt to /dashboard. Message: {token_data.get('message', 'N/A')}")
            return custom_response(code=token_data.get('code', 500), message=token_data.get('message', 'Unauthorized'))

        # Get user info from the token data
        user_id = token_data.get('user_id')
        user_device_id = token_data.get('user_device_id')
        
        logger.info(f"Processing dashboard data request for user_id: {user_id}, user_device_id: {user_device_id}")

        # Set default pagination values
        page = 1
        limit = 10
        
        dashboard_data: Dict[str, List[Dict[str, Any]]] = {}
        
        # Step 2: Fetch category data
        logger.info("Fetching category data for the dashboard.")
        category_conditions = [
            Category.is_active.is_(True)
        ]

        category_stmt = (
            select(Category)
            .where(and_(*category_conditions))
            .order_by(Category.name.asc())
            .offset((page - 1) * limit)
            .limit(limit)
        )
        
        category_result = await db.execute(category_stmt)
        category_rows = category_result.scalars().all()
        
        categories_list = [
            {
                "category_id": c.category_id,
                "name": c.name,
                "description": c.description,
                "thumbnail_url": c.thumbnail_url,
                "is_free":c.is_free,
                "is_active": c.is_active,
                "sort_order": c.sort_order
            }
            for c in category_rows
        ]

        dashboard_data["categories"] = categories_list
        logger.info(f"Successfully retrieved {len(categories_list)} categories.")

        # Step 3: Conditionally fetch user history if user_id is present
        if user_id:
            logger.info(f"User ID present. Fetching user history for {user_id}.")
            history_conditions = [
                GeneratedTattooHistory.user_id == user_id,
                GeneratedTattooHistory.is_history.is_(True),
                GeneratedTattooHistory.is_delete == 0
            ]
            
            # history_stmt = (
            #     select(GeneratedTattooHistory)
                # .where(and_(*history_conditions))
                # .order_by(GeneratedTattooHistory.created_at.desc())
                # .offset((page - 1) * limit)
                # .limit(limit)
            # )

            history_stmt = (
                select(
                    GeneratedTattooHistory,
                    func.count().over().label('total_count'),
                    TattooStyle.category_id,
                    Category.name.label("category_name")
                )
                .outerjoin(
                    TattooStyle,
                    GeneratedTattooHistory.tattoo_style_id == TattooStyle.style_id
                )
                .outerjoin(
                    Category,
                    TattooStyle.category_id == Category.category_id
                )
                .where(and_(*history_conditions))
                .order_by(GeneratedTattooHistory.created_at.desc())
                .offset((page - 1) * limit)
                .limit(limit)
            )

            history_result = await db.execute(history_stmt)
            history_rows = history_result.all()

            print("History Rows: ", history_rows)
            
            # history_list = [
            #     {
            #         "history_id": h.history_id,
            #         "user_id": h.user_id,
            #         "name": h.name,
            #         "image_url": h.image_url,
            #         "created_at": h.created_at
            #     }
            #     for h in history_rows
            # ]

            history_list = [
                {
                    "history_id": h.history_id,
                    "user_id": h.user_id,
                    "name": h.name,
                    "image_url": h.image_url,
                    "created_at": h.created_at,
                    "category_id": category_id,
                    "category_name": category_name,
                }
                for h, total_count, category_id, category_name in history_rows
            ]
            
            
            dashboard_data["history"] = history_list
            logger.info(f"Successfully retrieved {len(history_list)} history items.")
        else:
            dashboard_data["history"] = []
            logger.info("No user ID found in token, skipping history fetch.")
        
        logger.info("Dashboard data retrieved successfully.")
        return custom_response(code=200, data=dashboard_data, message="Dashboard data retrieved successfully")

    except Exception as e:
        logger.error(f"Internal server error in /dashboard: {e}", exc_info=True)
        return custom_response(code=500, message="Internal server error")
