"""
User onboarding progress API routes
"""

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Dict, Any, List, Optional
import structlog
from datetime import datetime, timezone
from pydantic import BaseModel

from app.core.database import get_db
from app.services.user_service import UserService
from app.repositories.onboarding_repository import OnboardingRepository
from shared.auth.decorators import get_current_user_dep

logger = structlog.get_logger()
router = APIRouter(tags=["onboarding"])

# Request/Response Models
class OnboardingStepStatus(BaseModel):
    step_name: str
    completed: bool
    completed_at: Optional[datetime] = None
    data: Optional[Dict[str, Any]] = None

class UserProgress(BaseModel):
    user_id: str
    steps: List[OnboardingStepStatus]
    current_step: str
    next_step: Optional[str] = None
    completion_percentage: float
    fully_completed: bool
    last_updated: datetime

class UpdateStepRequest(BaseModel):
    step_name: str
    completed: bool
    data: Optional[Dict[str, Any]] = None

# Define the onboarding steps and their order - matching frontend step IDs
ONBOARDING_STEPS = [
    "user_registered",         # Auto-completed: User account created
    "setup",                   # Step 1: Basic bakery setup and tenant creation
    "smart-inventory-setup",   # Step 2: Sales data upload and inventory configuration
    "suppliers",               # Step 3: Suppliers configuration (optional)
    "ml-training",             # Step 4: AI model training
    "completion"               # Step 5: Onboarding completed, ready to use dashboard
]

STEP_DEPENDENCIES = {
    "setup": ["user_registered"],
    "smart-inventory-setup": ["user_registered", "setup"],
    "suppliers": ["user_registered", "setup", "smart-inventory-setup"],  # Optional step
    "ml-training": ["user_registered", "setup", "smart-inventory-setup"],
    "completion": ["user_registered", "setup", "smart-inventory-setup", "ml-training"]
}

class OnboardingService:
    """Service for managing user onboarding progress"""
    
    def __init__(self, db: AsyncSession):
        self.db = db
        self.user_service = UserService(db)
        self.onboarding_repo = OnboardingRepository(db)
    
    async def get_user_progress(self, user_id: str) -> UserProgress:
        """Get current onboarding progress for user"""
        
        # Get user's onboarding data from user preferences or separate table
        user_progress_data = await self._get_user_onboarding_data(user_id)
        
        # Calculate current status for each step
        steps = []
        completed_steps = []
        
        for step_name in ONBOARDING_STEPS:
            step_data = user_progress_data.get(step_name, {})
            is_completed = step_data.get("completed", False)
            
            if is_completed:
                completed_steps.append(step_name)
            
            steps.append(OnboardingStepStatus(
                step_name=step_name,
                completed=is_completed,
                completed_at=step_data.get("completed_at"),
                data=step_data.get("data", {})
            ))
        
        # Determine current and next step
        current_step = self._get_current_step(completed_steps)
        next_step = self._get_next_step(completed_steps)
        
        # Calculate completion percentage
        completion_percentage = (len(completed_steps) / len(ONBOARDING_STEPS)) * 100
        
        # Check if fully completed
        fully_completed = len(completed_steps) == len(ONBOARDING_STEPS)
        
        return UserProgress(
            user_id=user_id,
            steps=steps,
            current_step=current_step,
            next_step=next_step,
            completion_percentage=completion_percentage,
            fully_completed=fully_completed,
            last_updated=datetime.now(timezone.utc)
        )
    
    async def update_step(self, user_id: str, update_request: UpdateStepRequest) -> UserProgress:
        """Update a specific onboarding step"""
        
        step_name = update_request.step_name
        
        # Validate step name
        if step_name not in ONBOARDING_STEPS:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Invalid step name: {step_name}"
            )
        
        # Check dependencies if marking as completed
        if update_request.completed:
            can_complete = await self._can_complete_step(user_id, step_name)
            if not can_complete:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail=f"Cannot complete step {step_name}: dependencies not met"
                )
        
        # Update the step
        await self._update_user_onboarding_data(
            user_id, 
            step_name, 
            {
                "completed": update_request.completed,
                "completed_at": datetime.now(timezone.utc).isoformat() if update_request.completed else None,
                "data": update_request.data or {}
            }
        )
        
        # Return updated progress
        return await self.get_user_progress(user_id)
    
    async def get_next_step(self, user_id: str) -> Dict[str, Any]:
        """Get the next required step for user"""
        progress = await self.get_user_progress(user_id)
        
        if progress.fully_completed:
            return {"step": "dashboard_accessible", "completed": True}
        
        return {"step": progress.next_step or progress.current_step}
    
    async def can_access_step(self, user_id: str, step_name: str) -> Dict[str, Any]:
        """Check if user can access a specific step"""
        
        if step_name not in ONBOARDING_STEPS:
            return {"can_access": False, "reason": "Invalid step name"}
        
        can_access = await self._can_complete_step(user_id, step_name)
        return {"can_access": can_access}
    
    async def complete_onboarding(self, user_id: str) -> Dict[str, Any]:
        """Mark entire onboarding as complete"""
        
        # Ensure all steps are completed
        progress = await self.get_user_progress(user_id)
        
        if not progress.fully_completed:
            incomplete_steps = [
                step.step_name for step in progress.steps if not step.completed
            ]
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Cannot complete onboarding: incomplete steps: {incomplete_steps}"
            )
        
        # Update user's isOnboardingComplete flag
        await self.user_service.update_user_field(
            user_id, 
            "is_onboarding_complete", 
            True
        )
        
        return {"success": True, "message": "Onboarding completed successfully"}
    
    def _get_current_step(self, completed_steps: List[str]) -> str:
        """Determine current step based on completed steps"""
        for step in ONBOARDING_STEPS:
            if step not in completed_steps:
                return step
        return ONBOARDING_STEPS[-1]  # All completed
    
    def _get_next_step(self, completed_steps: List[str]) -> Optional[str]:
        """Determine next step based on completed steps"""
        current_step = self._get_current_step(completed_steps)
        current_index = ONBOARDING_STEPS.index(current_step)
        
        if current_index < len(ONBOARDING_STEPS) - 1:
            return ONBOARDING_STEPS[current_index + 1]
        
        return None  # No next step
    
    async def _can_complete_step(self, user_id: str, step_name: str) -> bool:
        """Check if user can complete a specific step"""
        
        # Get required dependencies for this step
        required_steps = STEP_DEPENDENCIES.get(step_name, [])
        
        if not required_steps:
            return True  # No dependencies
        
        # Check if all required steps are completed
        user_progress_data = await self._get_user_onboarding_data(user_id)
        
        for required_step in required_steps:
            if not user_progress_data.get(required_step, {}).get("completed", False):
                return False
        
        # SPECIAL VALIDATION FOR ML TRAINING STEP
        if step_name == "ml-training":
            # Ensure that smart-inventory-setup was completed with sales data imported
            smart_inventory_data = user_progress_data.get("smart-inventory-setup", {}).get("data", {})
            
            # Check if sales data was imported successfully
            sales_import_result = smart_inventory_data.get("salesImportResult", {})
            has_sales_data_imported = (
                sales_import_result.get("records_created", 0) > 0 or 
                sales_import_result.get("success", False) or
                sales_import_result.get("imported", False)
            )
            
            if not has_sales_data_imported:
                logger.warning(f"ML training blocked for user {user_id}: No sales data imported", 
                             extra={"sales_import_result": sales_import_result})
                return False
                
            # Also check if inventory is configured
            inventory_configured = smart_inventory_data.get("inventoryConfigured", False)
            if not inventory_configured:
                logger.warning(f"ML training blocked for user {user_id}: Inventory not configured")
                return False
        
        return True
    
    async def _get_user_onboarding_data(self, user_id: str) -> Dict[str, Any]:
        """Get user's onboarding progress data from storage"""
        try:
            # Get all onboarding steps for the user from database
            steps = await self.onboarding_repo.get_user_progress_steps(user_id)
            
            # Convert to the expected dictionary format
            progress_data = {}
            for step in steps:
                progress_data[step.step_name] = {
                    "completed": step.completed,
                    "completed_at": step.completed_at,
                    "data": step.step_data or {}
                }
            
            return progress_data
            
        except Exception as e:
            logger.error(f"Error getting onboarding data for user {user_id}: {e}")
            return {}
    
    async def _update_user_onboarding_data(
        self, 
        user_id: str, 
        step_name: str, 
        step_data: Dict[str, Any]
    ):
        """Update user's onboarding step data"""
        try:
            # Extract the completion status and other data
            completed = step_data.get("completed", False)
            data_payload = step_data.get("data", {})
            
            # Update the step in database
            updated_step = await self.onboarding_repo.upsert_user_step(
                user_id=user_id,
                step_name=step_name,
                completed=completed,
                step_data=data_payload
            )
            
            # Update the user's onboarding summary
            await self._update_user_summary(user_id)
            
            logger.info(f"Successfully updated onboarding step for user {user_id}: {step_name} = {step_data}")
            return updated_step
            
        except Exception as e:
            logger.error(f"Error updating onboarding data for user {user_id}, step {step_name}: {e}")
            raise
    
    async def _update_user_summary(self, user_id: str):
        """Update user's onboarding summary after step changes"""
        try:
            # Get updated progress
            user_progress_data = await self._get_user_onboarding_data(user_id)
            
            # Calculate current status
            completed_steps = []
            for step_name in ONBOARDING_STEPS:
                if user_progress_data.get(step_name, {}).get("completed", False):
                    completed_steps.append(step_name)
            
            # Determine current and next step
            current_step = self._get_current_step(completed_steps)
            next_step = self._get_next_step(completed_steps)
            
            # Calculate completion percentage
            completion_percentage = (len(completed_steps) / len(ONBOARDING_STEPS)) * 100
            
            # Check if fully completed
            fully_completed = len(completed_steps) == len(ONBOARDING_STEPS)
            
            # Format steps count
            steps_completed_count = f"{len(completed_steps)}/{len(ONBOARDING_STEPS)}"
            
            # Update summary in database
            await self.onboarding_repo.upsert_user_summary(
                user_id=user_id,
                current_step=current_step,
                next_step=next_step,
                completion_percentage=completion_percentage,
                fully_completed=fully_completed,
                steps_completed_count=steps_completed_count
            )
            
        except Exception as e:
            logger.error(f"Error updating onboarding summary for user {user_id}: {e}")
            # Don't raise here - summary update failure shouldn't break step updates

# API Routes

@router.get("/me/onboarding/progress", response_model=UserProgress)
async def get_user_progress(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """Get current user's onboarding progress"""
    
    try:
        onboarding_service = OnboardingService(db)
        progress = await onboarding_service.get_user_progress(current_user["user_id"])
        return progress
        
    except Exception as e:
        logger.error(f"Get onboarding progress error: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to get onboarding progress"
        )

@router.put("/me/onboarding/step", response_model=UserProgress)
async def update_onboarding_step(
    update_request: UpdateStepRequest,
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """Update a specific onboarding step"""
    
    try:
        onboarding_service = OnboardingService(db)
        progress = await onboarding_service.update_step(
            current_user["user_id"], 
            update_request
        )
        return progress
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Update onboarding step error: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to update onboarding step"
        )

@router.get("/me/onboarding/next-step")
async def get_next_step(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """Get next required step for user"""
    
    try:
        onboarding_service = OnboardingService(db)
        result = await onboarding_service.get_next_step(current_user["user_id"])
        return result
        
    except Exception as e:
        logger.error(f"Get next step error: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to get next step"
        )

@router.get("/me/onboarding/can-access/{step_name}")
async def can_access_step(
    step_name: str,
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """Check if user can access a specific step"""
    
    try:
        onboarding_service = OnboardingService(db)
        result = await onboarding_service.can_access_step(
            current_user["user_id"], 
            step_name
        )
        return result
        
    except Exception as e:
        logger.error(f"Can access step error: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to check step access"
        )

@router.post("/me/onboarding/complete")
async def complete_onboarding(
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """Complete entire onboarding process"""
    
    try:
        onboarding_service = OnboardingService(db)
        result = await onboarding_service.complete_onboarding(current_user["user_id"])
        return result
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Complete onboarding error: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to complete onboarding"
        )