"""
Distribution Service Client for Inter-Service Communication

This client provides a high-level API for interacting with the Distribution Service,
which manages delivery routes, shipment tracking, and vehicle routing optimization for
enterprise multi-location bakery networks.

Key Capabilities:
- Generate daily distribution plans using VRP (Vehicle Routing Problem) optimization
- Manage delivery routes with driver assignments and route sequencing
- Track shipments from pending → packed → in_transit → delivered
- Update shipment status with proof of delivery (POD) metadata
- Filter routes and shipments by date range and status
- Setup enterprise distribution for demo sessions

Enterprise Context:
- Designed for parent-child tenant hierarchies (central production + retail outlets)
- Routes optimize deliveries from parent (central bakery) to children (outlets)
- Integrates with Procurement Service (internal transfer POs) and Inventory Service (stock transfers)
- Publishes shipment.delivered events for inventory ownership transfer

Usage Example:
    ```python
    from shared.clients import create_distribution_client
    from shared.config.base import get_settings

    config = get_settings()
    client = create_distribution_client(config, service_name="orchestrator")

    # Generate daily distribution plan
    plan = await client.generate_daily_distribution_plan(
        tenant_id=parent_tenant_id,
        target_date=date.today(),
        vehicle_capacity_kg=1000.0
    )

    # Get active delivery routes
    routes = await client.get_delivery_routes(
        tenant_id=parent_tenant_id,
        status="in_progress"
    )

    # Update shipment to delivered
    await client.update_shipment_status(
        tenant_id=parent_tenant_id,
        shipment_id=shipment_id,
        new_status="delivered",
        user_id=driver_id,
        metadata={"signature": "...", "photo_url": "..."}
    )
    ```

Service Architecture:
- Base URL: Configured via DISTRIBUTION_SERVICE_URL environment variable
- Authentication: Uses BaseServiceClient with tenant_id header validation
- Error Handling: Returns None on errors, logs detailed error context
- Async: All methods are async and use httpx for HTTP communication

Related Services:
- Procurement Service: Approved internal transfer POs feed into distribution planning
- Inventory Service: Consumes shipment.delivered events for stock ownership transfer
- Tenant Service: Validates parent-child tenant relationships and location data
- Orchestrator Service: Enterprise dashboard displays delivery route status

For more details, see services/distribution/README.md
"""

import structlog
from typing import Dict, Any, List, Optional
from datetime import date
from shared.clients.base_service_client import BaseServiceClient
from shared.config.base import BaseServiceSettings

logger = structlog.get_logger()


class DistributionServiceClient(BaseServiceClient):
    """Client for communicating with the Distribution Service"""

    def __init__(self, config: BaseServiceSettings, service_name: str = "unknown"):
        super().__init__(service_name, config)
        self.service_base_url = config.DISTRIBUTION_SERVICE_URL

    def get_service_base_path(self) -> str:
        return "/api/v1"

    # ================================================================
    # DAILY DISTRIBUTION PLAN ENDPOINTS
    # ================================================================

    async def generate_daily_distribution_plan(
        self,
        tenant_id: str,
        target_date: date,
        vehicle_capacity_kg: float = 1000.0
    ) -> Optional[Dict[str, Any]]:
        """
        Generate daily distribution plan for internal transfers

        Args:
            tenant_id: Tenant ID (should be parent tenant for enterprise)
            target_date: Date for which to generate distribution plan
            vehicle_capacity_kg: Maximum capacity per vehicle

        Returns:
            Distribution plan details
        """
        try:
            response = await self.post(
                f"tenants/{tenant_id}/distribution/plans/generate",
                data={
                    "target_date": target_date.isoformat(),
                    "vehicle_capacity_kg": vehicle_capacity_kg
                },
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Generated daily distribution plan",
                           tenant_id=tenant_id,
                           target_date=target_date.isoformat())
            return response
        except Exception as e:
            logger.error("Error generating distribution plan",
                        tenant_id=tenant_id,
                        target_date=target_date,
                        error=str(e))
            return None

    # ================================================================
    # DELIVERY ROUTES ENDPOINTS
    # ================================================================

    async def get_delivery_routes(
        self,
        tenant_id: str,
        date_from: Optional[date] = None,
        date_to: Optional[date] = None,
        status: Optional[str] = None
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get delivery routes with optional filtering

        Args:
            tenant_id: Tenant ID
            date_from: Start date for filtering
            date_to: End date for filtering
            status: Status filter

        Returns:
            List of delivery route dictionaries
        """
        try:
            params = {}
            if date_from:
                params["date_from"] = date_from.isoformat()
            if date_to:
                params["date_to"] = date_to.isoformat()
            if status:
                params["status"] = status

            # Use _make_request directly to construct correct URL
            # Gateway route: /api/v1/tenants/{tenant_id}/distribution/{path}
            response = await self._make_request(
                "GET",
                f"tenants/{tenant_id}/distribution/routes",
                params=params
            )

            if response:
                # Handle different response formats
                if isinstance(response, list):
                    # Direct list of routes
                    logger.info("Retrieved delivery routes",
                               tenant_id=tenant_id,
                               count=len(response))
                    return response
                elif isinstance(response, dict):
                    # Response wrapped in routes key
                    if "routes" in response:
                        logger.info("Retrieved delivery routes",
                                   tenant_id=tenant_id,
                                   count=len(response.get("routes", [])))
                        return response.get("routes", [])
                    else:
                        # Return the whole dict if it's a single route
                        logger.info("Retrieved delivery routes",
                                   tenant_id=tenant_id,
                                   count=1)
                        return [response]
            logger.info("No delivery routes found",
                       tenant_id=tenant_id)
            return []
        except Exception as e:
            logger.error("Error getting delivery routes",
                        tenant_id=tenant_id,
                        error=str(e))
            return []

    async def get_delivery_route_detail(
        self,
        tenant_id: str,
        route_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Get detailed information about a specific delivery route

        Args:
            tenant_id: Tenant ID
            route_id: Route ID

        Returns:
            Delivery route details
        """
        try:
            response = await self.get(
                f"distribution/routes/{route_id}",
                tenant_id=tenant_id
            )

            if response:
                logger.info("Retrieved delivery route detail",
                           tenant_id=tenant_id,
                           route_id=route_id)
                # Ensure we return the route data directly if it's wrapped in a route key
                if isinstance(response, dict) and "route" in response:
                    return response["route"]
            return response
        except Exception as e:
            logger.error("Error getting delivery route detail",
                        tenant_id=tenant_id,
                        route_id=route_id,
                        error=str(e))
            return None

    # ================================================================
    # SHIPMENT ENDPOINTS
    # ================================================================

    async def get_shipments(
        self,
        tenant_id: str,
        date_from: Optional[date] = None,
        date_to: Optional[date] = None,
        status: Optional[str] = None
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get shipments with optional filtering

        Args:
            tenant_id: Tenant ID
            date_from: Start date for filtering
            date_to: End date for filtering
            status: Status filter

        Returns:
            List of shipment dictionaries
        """
        try:
            params = {}
            if date_from:
                params["date_from"] = date_from.isoformat()
            if date_to:
                params["date_to"] = date_to.isoformat()
            if status:
                params["status"] = status

            # Use _make_request directly to construct correct URL
            # Gateway route: /api/v1/tenants/{tenant_id}/distribution/{path}
            response = await self._make_request(
                "GET",
                f"tenants/{tenant_id}/distribution/shipments",
                params=params
            )

            if response:
                # Handle different response formats
                if isinstance(response, list):
                    # Direct list of shipments
                    logger.info("Retrieved shipments",
                               tenant_id=tenant_id,
                               count=len(response))
                    return response
                elif isinstance(response, dict):
                    # Response wrapped in shipments key
                    if "shipments" in response:
                        logger.info("Retrieved shipments",
                                   tenant_id=tenant_id,
                                   count=len(response.get("shipments", [])))
                        return response.get("shipments", [])
                    else:
                        # Return the whole dict if it's a single shipment
                        logger.info("Retrieved shipments",
                                   tenant_id=tenant_id,
                                   count=1)
                        return [response]
            logger.info("No shipments found",
                       tenant_id=tenant_id)
            return []
        except Exception as e:
            logger.error("Error getting shipments",
                        tenant_id=tenant_id,
                        error=str(e))
            return []

    async def get_shipment_detail(
        self,
        tenant_id: str,
        shipment_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Get detailed information about a specific shipment

        Args:
            tenant_id: Tenant ID
            shipment_id: Shipment ID

        Returns:
            Shipment details
        """
        try:
            response = await self.get(
                f"distribution/shipments/{shipment_id}",
                tenant_id=tenant_id
            )

            if response:
                logger.info("Retrieved shipment detail",
                           tenant_id=tenant_id,
                           shipment_id=shipment_id)
                # Ensure we return the shipment data directly if it's wrapped in a shipment key
                if isinstance(response, dict) and "shipment" in response:
                    return response["shipment"]
            return response
        except Exception as e:
            logger.error("Error getting shipment detail",
                        tenant_id=tenant_id,
                        shipment_id=shipment_id,
                        error=str(e))
            return None

    async def update_shipment_status(
        self,
        tenant_id: str,
        shipment_id: str,
        new_status: str,
        user_id: str,
        metadata: Optional[Dict[str, Any]] = None
    ) -> Optional[Dict[str, Any]]:
        """
        Update shipment status

        Args:
            tenant_id: Tenant ID
            shipment_id: Shipment ID
            new_status: New status
            user_id: User ID performing update
            metadata: Additional metadata for the update

        Returns:
            Updated shipment details
        """
        try:
            payload = {
                "status": new_status,
                "updated_by_user_id": user_id,
                "metadata": metadata or {}
            }

            response = await self.put(
                f"distribution/shipments/{shipment_id}/status",
                data=payload,
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Updated shipment status",
                           tenant_id=tenant_id,
                           shipment_id=shipment_id,
                           new_status=new_status)
            return response
        except Exception as e:
            logger.error("Error updating shipment status",
                        tenant_id=tenant_id,
                        shipment_id=shipment_id,
                        new_status=new_status,
                        error=str(e))
            return None

    # ================================================================
    # INTERNAL DEMO ENDPOINTS
    # ================================================================

    # Legacy setup_enterprise_distribution_demo method removed
    # Distribution now uses standard /internal/demo/clone endpoint via DataCloner

    async def get_shipments_for_date(
        self,
        tenant_id: str,
        target_date: date
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get all shipments for a specific date

        Args:
            tenant_id: Tenant ID
            target_date: Target date

        Returns:
            List of shipments for the date
        """
        try:
            # Use _make_request directly to construct correct URL
            # Gateway route: /api/v1/tenants/{tenant_id}/distribution/{path}
            response = await self._make_request(
                "GET",
                f"tenants/{tenant_id}/distribution/shipments",
                params={
                    "date_from": target_date.isoformat(),
                    "date_to": target_date.isoformat()
                }
            )

            if response:
                # Handle different response formats
                if isinstance(response, list):
                    # Direct list of shipments
                    logger.info("Retrieved shipments for date",
                               tenant_id=tenant_id,
                               target_date=target_date.isoformat(),
                               shipment_count=len(response))
                    return response
                elif isinstance(response, dict):
                    # Response wrapped in shipments key
                    if "shipments" in response:
                        logger.info("Retrieved shipments for date",
                                   tenant_id=tenant_id,
                                   target_date=target_date.isoformat(),
                                   shipment_count=len(response.get("shipments", [])))
                        return response.get("shipments", [])
                    else:
                        # Return the whole dict if it's a single shipment
                        logger.info("Retrieved shipments for date",
                                   tenant_id=tenant_id,
                                   target_date=target_date.isoformat(),
                                   shipment_count=1)
                        return [response]
            logger.info("No shipments found for date",
                       tenant_id=tenant_id,
                       target_date=target_date.isoformat())
            return []
        except Exception as e:
            logger.error("Error getting shipments for date",
                        tenant_id=tenant_id,
                        target_date=target_date,
                        error=str(e))
            return []

    # ================================================================
    # HEALTH CHECK
    # ================================================================

    async def health_check(self) -> bool:
        """Check if distribution service is healthy"""
        try:
            # Use base health check method
            response = await self.get("health")
            return response is not None
        except Exception as e:
            logger.error("Distribution service health check failed", error=str(e))
            return False


# Factory function for dependency injection
def create_distribution_client(config: BaseServiceSettings, service_name: str = "unknown") -> DistributionServiceClient:
    """Create distribution service client instance"""
    return DistributionServiceClient(config, service_name)
