"""
Tenant Hierarchy API - Handles parent-child tenant relationships
"""

from fastapi import APIRouter, Depends, HTTPException, status, Path
from typing import List, Dict, Any
from uuid import UUID

from app.schemas.tenants import (
    TenantResponse,
    ChildTenantCreate,
    BulkChildTenantsCreate,
    BulkChildTenantsResponse,
    ChildTenantResponse,
    TenantHierarchyResponse
)
from app.services.tenant_service import EnhancedTenantService
from app.repositories.tenant_repository import TenantRepository
from shared.auth.decorators import get_current_user_dep
from shared.routing.route_builder import RouteBuilder
from shared.database.base import create_database_manager
from shared.monitoring.metrics import track_endpoint_metrics
import structlog

logger = structlog.get_logger()
router = APIRouter()
route_builder = RouteBuilder("tenants")


# Dependency injection for enhanced tenant service
def get_enhanced_tenant_service():
    try:
        from app.core.config import settings
        database_manager = create_database_manager(settings.DATABASE_URL, "tenant-service")
        return EnhancedTenantService(database_manager)
    except Exception as e:
        logger.error("Failed to create enhanced tenant service", error=str(e))
        raise HTTPException(status_code=500, detail="Service initialization failed")


@router.get(route_builder.build_base_route("{tenant_id}/children", include_tenant_prefix=False), response_model=List[TenantResponse])
@track_endpoint_metrics("tenant_children_list")
async def get_tenant_children(
    tenant_id: UUID = Path(..., description="Parent Tenant ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
):
    """
    Get all child tenants for a parent tenant.
    This endpoint returns all active child tenants associated with the specified parent tenant.
    """
    try:
        logger.info(
            "Get tenant children request received",
            tenant_id=str(tenant_id),
            user_id=current_user.get("user_id"),
            user_type=current_user.get("type", "user"),
            is_service=current_user.get("type") == "service",
            role=current_user.get("role"),
            service_name=current_user.get("service", "none")
        )

        # Skip access check for service-to-service calls
        is_service_call = current_user.get("type") == "service"
        if not is_service_call:
            # Verify user has access to the parent tenant
            access_info = await tenant_service.verify_user_access(current_user["user_id"], str(tenant_id))
            if not access_info.has_access:
                logger.warning(
                    "Access denied to parent tenant",
                    tenant_id=str(tenant_id),
                    user_id=current_user.get("user_id")
                )
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Access denied to parent tenant"
                )
        else:
            logger.debug(
                "Service-to-service call - bypassing access check",
                service=current_user.get("service"),
                tenant_id=str(tenant_id)
            )

        # Get child tenants from repository
        from app.models.tenants import Tenant
        async with tenant_service.database_manager.get_session() as session:
            tenant_repo = TenantRepository(Tenant, session)
            child_tenants = await tenant_repo.get_child_tenants(str(tenant_id))

            logger.debug(
                "Get tenant children successful",
                tenant_id=str(tenant_id),
                child_count=len(child_tenants)
            )

            # Convert to plain dicts while still in session to avoid lazy-load issues
            child_dicts = []
            for child in child_tenants:
                # Handle subscription_tier safely - avoid lazy load
                try:
                    # Try to get subscription_tier if subscriptions are already loaded
                    sub_tier = child.__dict__.get('_subscription_tier_cache', 'enterprise')
                except:
                    sub_tier = 'enterprise'  # Default for enterprise children

                child_dict = {
                    'id': str(child.id),
                    'name': child.name,
                    'subdomain': child.subdomain,
                    'business_type': child.business_type,
                    'business_model': child.business_model,
                    'address': child.address,
                    'city': child.city,
                    'postal_code': child.postal_code,
                    'latitude': child.latitude,
                    'longitude': child.longitude,
                    'phone': child.phone,
                    'email': child.email,
                    'timezone': child.timezone,
                    'owner_id': str(child.owner_id),
                    'parent_tenant_id': str(child.parent_tenant_id) if child.parent_tenant_id else None,
                    'tenant_type': child.tenant_type,
                    'hierarchy_path': child.hierarchy_path,
                    'subscription_tier': sub_tier,  # Use the safely retrieved value
                    'ml_model_trained': child.ml_model_trained,
                    'last_training_date': child.last_training_date,
                    'is_active': child.is_active,
                    'is_demo': child.is_demo,
                    'demo_session_id': child.demo_session_id,
                    'created_at': child.created_at,
                    'updated_at': child.updated_at
                }
                child_dicts.append(child_dict)

        # Convert to Pydantic models outside the session without from_attributes
        child_responses = [TenantResponse(**child_dict) for child_dict in child_dicts]
        return child_responses

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Get tenant children failed",
                    tenant_id=str(tenant_id),
                    user_id=current_user.get("user_id"),
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Get tenant children failed"
        )


@router.get(route_builder.build_base_route("{tenant_id}/children/count", include_tenant_prefix=False))
@track_endpoint_metrics("tenant_children_count")
async def get_tenant_children_count(
    tenant_id: UUID = Path(..., description="Parent Tenant ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
):
    """
    Get count of child tenants for a parent tenant.
    This endpoint returns the number of active child tenants associated with the specified parent tenant.
    """
    try:
        logger.info(
            "Get tenant children count request received",
            tenant_id=str(tenant_id),
            user_id=current_user.get("user_id")
        )

        # Skip access check for service-to-service calls
        is_service_call = current_user.get("type") == "service"
        if not is_service_call:
            # Verify user has access to the parent tenant
            access_info = await tenant_service.verify_user_access(current_user["user_id"], str(tenant_id))
            if not access_info.has_access:
                logger.warning(
                    "Access denied to parent tenant",
                    tenant_id=str(tenant_id),
                    user_id=current_user.get("user_id")
                )
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Access denied to parent tenant"
                )
        else:
            logger.debug(
                "Service-to-service call - bypassing access check",
                service=current_user.get("service"),
                tenant_id=str(tenant_id)
            )

        # Get child count from repository
        from app.models.tenants import Tenant
        async with tenant_service.database_manager.get_session() as session:
            tenant_repo = TenantRepository(Tenant, session)
            child_count = await tenant_repo.get_child_tenant_count(str(tenant_id))

        logger.debug(
            "Get tenant children count successful",
            tenant_id=str(tenant_id),
            child_count=child_count
        )

        return {
            "parent_tenant_id": str(tenant_id),
            "child_count": child_count
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Get tenant children count failed",
                    tenant_id=str(tenant_id),
                    user_id=current_user.get("user_id"),
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Get tenant children count failed"
        )


@router.get(route_builder.build_base_route("{tenant_id}/hierarchy", include_tenant_prefix=False), response_model=TenantHierarchyResponse)
@track_endpoint_metrics("tenant_hierarchy")
async def get_tenant_hierarchy(
    tenant_id: UUID = Path(..., description="Tenant ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
):
    """
    Get tenant hierarchy information.

    Returns hierarchy metadata for a tenant including:
    - Tenant type (standalone, parent, child)
    - Parent tenant ID (if this is a child)
    - Hierarchy path (materialized path)
    - Number of child tenants (for parent tenants)
    - Hierarchy level (depth in the tree)

    This endpoint is used by the authentication layer for hierarchical access control
    and by enterprise features for network management.
    """
    try:
        logger.info(
            "Get tenant hierarchy request received",
            tenant_id=str(tenant_id),
            user_id=current_user.get("user_id"),
            user_type=current_user.get("type", "user"),
            is_service=current_user.get("type") == "service"
        )

        # Get tenant from database
        from app.models.tenants import Tenant
        async with tenant_service.database_manager.get_session() as session:
            tenant_repo = TenantRepository(Tenant, session)

            # Get the tenant
            tenant = await tenant_repo.get(str(tenant_id))
            if not tenant:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail=f"Tenant {tenant_id} not found"
                )

            # Skip access check for service-to-service calls
            is_service_call = current_user.get("type") == "service"
            if not is_service_call:
                # Verify user has access to this tenant
                access_info = await tenant_service.verify_user_access(current_user["user_id"], str(tenant_id))
                if not access_info.has_access:
                    logger.warning(
                        "Access denied to tenant for hierarchy query",
                        tenant_id=str(tenant_id),
                        user_id=current_user.get("user_id")
                    )
                    raise HTTPException(
                        status_code=status.HTTP_403_FORBIDDEN,
                        detail="Access denied to tenant"
                    )
            else:
                logger.debug(
                    "Service-to-service call - bypassing access check",
                    service=current_user.get("service"),
                    tenant_id=str(tenant_id)
                )

            # Get child count if this is a parent tenant
            child_count = 0
            if tenant.tenant_type in ["parent", "standalone"]:
                child_count = await tenant_repo.get_child_tenant_count(str(tenant_id))

            # Calculate hierarchy level from hierarchy_path
            hierarchy_level = 0
            if tenant.hierarchy_path:
                # hierarchy_path format: "parent_id" or "parent_id.child_id" or "parent_id.child_id.grandchild_id"
                hierarchy_level = tenant.hierarchy_path.count('.')

            # Build response
            hierarchy_info = TenantHierarchyResponse(
                tenant_id=str(tenant.id),
                tenant_type=tenant.tenant_type or "standalone",
                parent_tenant_id=str(tenant.parent_tenant_id) if tenant.parent_tenant_id else None,
                hierarchy_path=tenant.hierarchy_path,
                child_count=child_count,
                hierarchy_level=hierarchy_level
            )

            logger.info(
                "Get tenant hierarchy successful",
                tenant_id=str(tenant_id),
                tenant_type=tenant.tenant_type,
                parent_tenant_id=str(tenant.parent_tenant_id) if tenant.parent_tenant_id else None,
                child_count=child_count,
                hierarchy_level=hierarchy_level
            )

            return hierarchy_info

    except HTTPException:
        raise
    except Exception as e:
        logger.error("Get tenant hierarchy failed",
                    tenant_id=str(tenant_id),
                    user_id=current_user.get("user_id"),
                    error=str(e))
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Get tenant hierarchy failed"
        )


@router.post("/api/v1/tenants/{tenant_id}/bulk-children", response_model=BulkChildTenantsResponse)
@track_endpoint_metrics("bulk_create_child_tenants")
async def bulk_create_child_tenants(
    request: BulkChildTenantsCreate,
    tenant_id: str = Path(..., description="Parent tenant ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    tenant_service: EnhancedTenantService = Depends(get_enhanced_tenant_service)
):
    """
    Bulk create child tenants for enterprise onboarding.

    This endpoint creates multiple child tenants (outlets/branches) for an enterprise parent tenant
    and establishes the parent-child relationship. It's designed for use during the onboarding flow
    when an enterprise customer registers their network of locations.

    Features:
    - Creates child tenants with proper hierarchy
    - Inherits subscription from parent
    - Optionally configures distribution routes
    - Returns detailed success/failure information
    """
    try:
        logger.info(
            "Bulk child tenant creation request received",
            parent_tenant_id=tenant_id,
            child_count=len(request.child_tenants),
            user_id=current_user.get("user_id")
        )

        # Verify parent tenant exists and user has access
        async with tenant_service.database_manager.get_session() as session:
            from app.models.tenants import Tenant
            tenant_repo = TenantRepository(Tenant, session)

            parent_tenant = await tenant_repo.get_by_id(tenant_id)
            if not parent_tenant:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail="Parent tenant not found"
                )

            # Verify user has access to parent tenant (owners/admins only)
            access_info = await tenant_service.verify_user_access(
                current_user["user_id"],
                tenant_id
            )
            if not access_info.has_access or access_info.role not in ["owner", "admin"]:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Only tenant owners/admins can create child tenants"
                )

            # Verify parent is enterprise tier
            parent_subscription = await tenant_service.subscription_repo.get_active_subscription(tenant_id)
            if not parent_subscription or parent_subscription.plan != "enterprise":
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="Only enterprise tier tenants can have child tenants"
                )

            # Update parent tenant type if it's still standalone
            if parent_tenant.tenant_type == "standalone":
                parent_tenant.tenant_type = "parent"
                parent_tenant.hierarchy_path = str(parent_tenant.id)
                await session.commit()
                await session.refresh(parent_tenant)

            # Create child tenants
            created_tenants = []
            failed_tenants = []

            for child_data in request.child_tenants:
                # Create a nested transaction (savepoint) for each child tenant
                # This allows us to rollback individual child tenant creation without affecting others
                async with session.begin_nested():
                    try:
                        # Create child tenant with full tenant model fields
                        child_tenant = Tenant(
                            name=child_data.name,
                            subdomain=None,  # Child tenants typically don't have subdomains
                            business_type=child_data.business_type or parent_tenant.business_type,
                            business_model=child_data.business_model or "retail_bakery",  # Child outlets are typically retail
                            address=child_data.address,
                            city=child_data.city,
                            postal_code=child_data.postal_code,
                            latitude=child_data.latitude,
                            longitude=child_data.longitude,
                            phone=child_data.phone or parent_tenant.phone,
                            email=child_data.email or parent_tenant.email,
                            timezone=child_data.timezone or parent_tenant.timezone,
                            owner_id=parent_tenant.owner_id,
                            parent_tenant_id=parent_tenant.id,
                            tenant_type="child",
                            hierarchy_path=f"{parent_tenant.hierarchy_path}",  # Will be updated after flush
                            is_active=True,
                            is_demo=parent_tenant.is_demo,
                            demo_session_id=parent_tenant.demo_session_id,
                            demo_expires_at=parent_tenant.demo_expires_at,
                            metadata_={
                                "location_code": child_data.location_code,
                                "zone": child_data.zone,
                                **(child_data.metadata or {})
                            }
                        )

                        session.add(child_tenant)
                        await session.flush()  # Get the ID without committing

                        # Update hierarchy_path now that we have the child tenant ID
                        child_tenant.hierarchy_path = f"{parent_tenant.hierarchy_path}.{str(child_tenant.id)}"

                        # Create TenantLocation record for the child
                        from app.models.tenant_location import TenantLocation
                        location = TenantLocation(
                            tenant_id=child_tenant.id,
                            name=child_data.name,
                            city=child_data.city,
                            address=child_data.address,
                            postal_code=child_data.postal_code,
                            latitude=child_data.latitude,
                            longitude=child_data.longitude,
                            is_active=True,
                            location_type="retail"
                        )
                        session.add(location)

                        # Inherit subscription from parent
                        from app.models.tenants import Subscription
                        from sqlalchemy import select
                        parent_subscription_result = await session.execute(
                            select(Subscription).where(
                                Subscription.tenant_id == parent_tenant.id,
                                Subscription.status == "active"
                            )
                        )
                        parent_sub = parent_subscription_result.scalar_one_or_none()

                        if parent_sub:
                            child_subscription = Subscription(
                                tenant_id=child_tenant.id,
                                plan=parent_sub.plan,
                                status="active",
                                billing_cycle=parent_sub.billing_cycle,
                                monthly_price=0,  # Child tenants don't pay separately
                                trial_ends_at=parent_sub.trial_ends_at
                            )
                            session.add(child_subscription)

                        # Commit the nested transaction (savepoint)
                        await session.flush()

                        # Refresh objects to get their final state
                        await session.refresh(child_tenant)
                        await session.refresh(location)

                        # Build response
                        created_tenants.append(ChildTenantResponse(
                            id=str(child_tenant.id),
                            name=child_tenant.name,
                            subdomain=child_tenant.subdomain,
                            business_type=child_tenant.business_type,
                            business_model=child_tenant.business_model,
                            tenant_type=child_tenant.tenant_type,
                            parent_tenant_id=str(child_tenant.parent_tenant_id),
                            address=child_tenant.address,
                            city=child_tenant.city,
                            postal_code=child_tenant.postal_code,
                            phone=child_tenant.phone,
                            is_active=child_tenant.is_active,
                            subscription_plan="enterprise",
                            ml_model_trained=child_tenant.ml_model_trained,
                            last_training_date=child_tenant.last_training_date,
                            owner_id=str(child_tenant.owner_id),
                            created_at=child_tenant.created_at,
                            location_code=child_data.location_code,
                            zone=child_data.zone,
                            hierarchy_path=child_tenant.hierarchy_path
                        ))

                        logger.info(
                            "Child tenant created successfully",
                            child_tenant_id=str(child_tenant.id),
                            child_name=child_tenant.name,
                            location_code=child_data.location_code
                        )

                    except Exception as child_error:
                        logger.error(
                            "Failed to create child tenant",
                            child_name=child_data.name,
                            error=str(child_error)
                        )
                        failed_tenants.append({
                            "name": child_data.name,
                            "location_code": child_data.location_code,
                            "error": str(child_error)
                        })
                        # Nested transaction will automatically rollback on exception
                        # This only rolls back the current child tenant, not the entire batch

            # Commit all successful child tenant creations
            await session.commit()

        # TODO: Configure distribution routes if requested
        distribution_configured = False
        if request.auto_configure_distribution and len(created_tenants) > 0:
            try:
                # This would call the distribution service to set up routes
                # For now, we'll skip this and just log
                logger.info(
                    "Distribution route configuration requested",
                    parent_tenant_id=tenant_id,
                    child_count=len(created_tenants)
                )
                # distribution_configured = await configure_distribution_routes(...)
            except Exception as dist_error:
                logger.warning(
                    "Failed to configure distribution routes",
                    error=str(dist_error)
                )

        logger.info(
            "Bulk child tenant creation completed",
            parent_tenant_id=tenant_id,
            created_count=len(created_tenants),
            failed_count=len(failed_tenants)
        )

        return BulkChildTenantsResponse(
            parent_tenant_id=tenant_id,
            created_count=len(created_tenants),
            failed_count=len(failed_tenants),
            created_tenants=created_tenants,
            failed_tenants=failed_tenants,
            distribution_configured=distribution_configured
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(
            "Bulk child tenant creation failed",
            parent_tenant_id=tenant_id,
            user_id=current_user.get("user_id"),
            error=str(e)
        )
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Bulk child tenant creation failed: {str(e)}"
        )


# Register the router in the main app
def register_hierarchy_routes(app):
    """Register hierarchy routes with the main application"""
    from shared.routing.route_builder import RouteBuilder
    route_builder = RouteBuilder("tenants")

    # Include the hierarchy routes with proper tenant prefix
    app.include_router(
        router,
        prefix="/api/v1",
        tags=["tenant-hierarchy"]
    )
