"""
Procurement Service Client for Inter-Service Communication
Provides API client for procurement operations and internal transfers
"""

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 ProcurementServiceClient(BaseServiceClient):
    """Client for communicating with the Procurement Service"""

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

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

    # ================================================================
    # PURCHASE ORDER ENDPOINTS
    # ================================================================

    async def create_purchase_order(
        self,
        tenant_id: str,
        order_data: Dict[str, Any]
    ) -> Optional[Dict[str, Any]]:
        """
        Create a new purchase order

        Args:
            tenant_id: Tenant ID
            order_data: Purchase order data

        Returns:
            Created purchase order
        """
        try:
            response = await self.post(
                "procurement/purchase-orders",
                data=order_data,
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Created purchase order",
                           tenant_id=tenant_id,
                           po_number=response.get("po_number"))
            return response
        except Exception as e:
            logger.error("Error creating purchase order",
                        tenant_id=tenant_id,
                        error=str(e))
            return None

    async def get_purchase_order(
        self,
        tenant_id: str,
        po_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Get a specific purchase order

        Args:
            tenant_id: Tenant ID
            po_id: Purchase order ID

        Returns:
            Purchase order details
        """
        try:
            response = await self.get(
                f"procurement/purchase-orders/{po_id}",
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Retrieved purchase order",
                           tenant_id=tenant_id,
                           po_id=po_id)
            return response
        except Exception as e:
            logger.error("Error getting purchase order",
                        tenant_id=tenant_id,
                        po_id=po_id,
                        error=str(e))
            return None

    async def update_purchase_order_status(
        self,
        tenant_id: str,
        po_id: str,
        new_status: str,
        user_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Update purchase order status

        Args:
            tenant_id: Tenant ID
            po_id: Purchase order ID
            new_status: New status
            user_id: User ID performing update

        Returns:
            Updated purchase order
        """
        try:
            response = await self.put(
                f"procurement/purchase-orders/{po_id}/status",
                data={
                    "status": new_status,
                    "updated_by_user_id": user_id
                },
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Updated purchase order status",
                           tenant_id=tenant_id,
                           po_id=po_id,
                           new_status=new_status)
            return response
        except Exception as e:
            logger.error("Error updating purchase order status",
                        tenant_id=tenant_id,
                        po_id=po_id,
                        new_status=new_status,
                        error=str(e))
            return None

    async def get_pending_purchase_orders(
        self,
        tenant_id: str,
        limit: int = 50,
        enrich_supplier: bool = True
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get pending purchase orders

        Args:
            tenant_id: Tenant ID
            limit: Maximum number of results
            enrich_supplier: Whether to include supplier details (default: True)
                           Set to False for faster queries when supplier data will be fetched separately

        Returns:
            List of pending purchase orders
        """
        try:
            response = await self.get(
                "procurement/purchase-orders",
                params={
                    "status": "pending_approval",
                    "limit": limit,
                    "enrich_supplier": enrich_supplier
                },
                tenant_id=tenant_id
            )

            if response:
                logger.info("Retrieved pending purchase orders",
                           tenant_id=tenant_id,
                           count=len(response),
                           enriched=enrich_supplier)
            return response if response else []
        except Exception as e:
            logger.error("Error getting pending purchase orders",
                        tenant_id=tenant_id,
                        error=str(e))
            return []

    async def get_purchase_orders_by_supplier(
        self,
        tenant_id: str,
        supplier_id: str,
        date_from: Optional[date] = None,
        date_to: Optional[date] = None,
        status: Optional[str] = None,
        limit: int = 100
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get purchase orders for a specific supplier

        Args:
            tenant_id: Tenant ID
            supplier_id: Supplier ID to filter by
            date_from: Start date for filtering
            date_to: End date for filtering
            status: Status filter (e.g., 'approved', 'delivered')
            limit: Maximum number of results

        Returns:
            List of purchase orders with items
        """
        try:
            params = {
                "supplier_id": supplier_id,
                "limit": limit
            }
            if date_from:
                params["date_from"] = date_from.isoformat()
            if date_to:
                params["date_to"] = date_to.isoformat()
            if status:
                params["status"] = status

            response = await self.get(
                "procurement/purchase-orders",
                params=params,
                tenant_id=tenant_id
            )

            if response:
                logger.info("Retrieved purchase orders by supplier",
                           tenant_id=tenant_id,
                           supplier_id=supplier_id,
                           count=len(response))
            return response if response else []
        except Exception as e:
            logger.error("Error getting purchase orders by supplier",
                        tenant_id=tenant_id,
                        supplier_id=supplier_id,
                        error=str(e))
            return []

    # ================================================================
    # INTERNAL TRANSFER ENDPOINTS (NEW FOR ENTERPRISE TIER)
    # ================================================================

    async def create_internal_purchase_order(
        self,
        parent_tenant_id: str,
        child_tenant_id: str,
        items: List[Dict[str, Any]],
        delivery_date: date,
        notes: Optional[str] = None
    ) -> Optional[Dict[str, Any]]:
        """
        Create an internal purchase order from parent to child tenant

        Args:
            parent_tenant_id: Parent tenant ID (supplier)
            child_tenant_id: Child tenant ID (buyer)
            items: List of items with product_id, quantity, unit_of_measure
            delivery_date: When child needs delivery
            notes: Optional notes for the transfer

        Returns:
            Created internal purchase order
        """
        try:
            response = await self.post(
                "procurement/internal-transfers",
                data={
                    "destination_tenant_id": child_tenant_id,
                    "items": items,
                    "delivery_date": delivery_date.isoformat(),
                    "notes": notes
                },
                tenant_id=parent_tenant_id
            )
            
            if response:
                logger.info("Created internal purchase order",
                           parent_tenant_id=parent_tenant_id,
                           child_tenant_id=child_tenant_id,
                           po_number=response.get("po_number"))
            return response
        except Exception as e:
            logger.error("Error creating internal purchase order",
                        parent_tenant_id=parent_tenant_id,
                        child_tenant_id=child_tenant_id,
                        error=str(e))
            return None

    async def get_approved_internal_purchase_orders(
        self,
        parent_tenant_id: str,
        target_date: Optional[date] = None,
        status: Optional[str] = "approved"
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get approved internal purchase orders for parent tenant

        Args:
            parent_tenant_id: Parent tenant ID
            target_date: Optional target date to filter
            status: Status filter (default: approved)

        Returns:
            List of approved internal purchase orders
        """
        try:
            params = {"status": status}
            if target_date:
                params["target_date"] = target_date.isoformat()

            response = await self.get(
                "procurement/internal-transfers",
                params=params,
                tenant_id=parent_tenant_id
            )
            
            if response:
                logger.info("Retrieved internal purchase orders",
                           parent_tenant_id=parent_tenant_id,
                           count=len(response))
            return response if response else []
        except Exception as e:
            logger.error("Error getting internal purchase orders",
                        parent_tenant_id=parent_tenant_id,
                        error=str(e))
            return []

    async def approve_internal_purchase_order(
        self,
        parent_tenant_id: str,
        po_id: str,
        approved_by_user_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Approve an internal purchase order

        Args:
            parent_tenant_id: Parent tenant ID
            po_id: Purchase order ID to approve
            approved_by_user_id: User ID performing approval

        Returns:
            Updated purchase order
        """
        try:
            response = await self.post(
                f"procurement/internal-transfers/{po_id}/approve",
                data={
                    "approved_by_user_id": approved_by_user_id
                },
                tenant_id=parent_tenant_id
            )
            
            if response:
                logger.info("Approved internal purchase order",
                           parent_tenant_id=parent_tenant_id,
                           po_id=po_id)
            return response
        except Exception as e:
            logger.error("Error approving internal purchase order",
                        parent_tenant_id=parent_tenant_id,
                        po_id=po_id,
                        error=str(e))
            return None

    async def get_internal_transfer_history(
        self,
        tenant_id: str,
        parent_tenant_id: Optional[str] = None,
        child_tenant_id: Optional[str] = None,
        start_date: Optional[date] = None,
        end_date: Optional[date] = None
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get internal transfer history with optional filtering

        Args:
            tenant_id: Tenant ID (either parent or child)
            parent_tenant_id: Filter by specific parent tenant
            child_tenant_id: Filter by specific child tenant
            start_date: Filter by start date
            end_date: Filter by end date

        Returns:
            List of internal transfer records
        """
        try:
            params = {}
            if parent_tenant_id:
                params["parent_tenant_id"] = parent_tenant_id
            if child_tenant_id:
                params["child_tenant_id"] = child_tenant_id
            if start_date:
                params["start_date"] = start_date.isoformat()
            if end_date:
                params["end_date"] = end_date.isoformat()

            response = await self.get(
                "procurement/internal-transfers/history",
                params=params,
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Retrieved internal transfer history",
                           tenant_id=tenant_id,
                           count=len(response))
            return response if response else []
        except Exception as e:
            logger.error("Error getting internal transfer history",
                        tenant_id=tenant_id,
                        error=str(e))
            return []

    # ================================================================
    # PROCUREMENT PLAN ENDPOINTS
    # ================================================================

    async def get_procurement_plan(
        self,
        tenant_id: str,
        plan_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Get a specific procurement plan

        Args:
            tenant_id: Tenant ID
            plan_id: Procurement plan ID

        Returns:
            Procurement plan details
        """
        try:
            response = await self.get(
                f"procurement/plans/{plan_id}",
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Retrieved procurement plan",
                           tenant_id=tenant_id,
                           plan_id=plan_id)
            return response
        except Exception as e:
            logger.error("Error getting procurement plan",
                        tenant_id=tenant_id,
                        plan_id=plan_id,
                        error=str(e))
            return None

    async def get_procurement_plans(
        self,
        tenant_id: str,
        date_from: Optional[date] = None,
        date_to: Optional[date] = None,
        status: Optional[str] = None
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get procurement plans 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 procurement plan 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

            response = await self.get(
                "procurement/plans",
                params=params,
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Retrieved procurement plans",
                           tenant_id=tenant_id,
                           count=len(response))
            return response if response else []
        except Exception as e:
            logger.error("Error getting procurement plans",
                        tenant_id=tenant_id,
                        error=str(e))
            return []

    # ================================================================
    # SUPPLIER ENDPOINTS
    # ================================================================

    async def get_suppliers(
        self,
        tenant_id: str
    ) -> Optional[List[Dict[str, Any]]]:
        """
        Get suppliers for a tenant

        Args:
            tenant_id: Tenant ID

        Returns:
            List of supplier dictionaries
        """
        try:
            response = await self.get(
                "procurement/suppliers",
                tenant_id=tenant_id
            )
            
            if response:
                logger.info("Retrieved suppliers",
                           tenant_id=tenant_id,
                           count=len(response))
            return response if response else []
        except Exception as e:
            logger.error("Error getting suppliers",
                        tenant_id=tenant_id,
                        error=str(e))
            return []

    async def get_supplier(
        self,
        tenant_id: str,
        supplier_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Get specific supplier details

        Args:
            tenant_id: Tenant ID
            supplier_id: Supplier ID

        Returns:
            Supplier details
        """
        try:
            # Use suppliers service to get supplier details
            from shared.clients.suppliers_client import SuppliersServiceClient
            suppliers_client = SuppliersServiceClient(self.config)
            response = await suppliers_client.get_supplier_by_id(tenant_id, supplier_id)
            
            if response:
                logger.info("Retrieved supplier details",
                           tenant_id=tenant_id,
                           supplier_id=supplier_id)
            return response
        except Exception as e:
            logger.error("Error getting supplier details",
                        tenant_id=tenant_id,
                        supplier_id=supplier_id,
                        error=str(e))
            return None

    # ================================================================
    # UTILITIES
    # ================================================================

    async def health_check(self) -> bool:
        """Check if procurement 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("Procurement service health check failed", error=str(e))
            return False

    # ================================================================
    # INTERNAL TRIGGER METHODS
    # ================================================================

    async def trigger_delivery_tracking_internal(
        self,
        tenant_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Trigger delivery tracking for a tenant (internal service use only).

        This method calls the internal endpoint which is protected by x-internal-service header.

        Args:
            tenant_id: Tenant ID to trigger delivery tracking for

        Returns:
            Dict with trigger results or None if failed
        """
        try:
            # Call internal endpoint via gateway using tenant-scoped URL pattern
            # Endpoint: /api/v1/tenants/{tenant_id}/procurement/internal/delivery-tracking/trigger
            result = await self._make_request(
                method="POST",
                endpoint="procurement/internal/delivery-tracking/trigger",
                tenant_id=tenant_id,
                data={},
                headers={"x-internal-service": "demo-session"}
            )

            if result:
                logger.info(
                    "Delivery tracking triggered successfully via internal endpoint",
                    tenant_id=tenant_id,
                    alerts_generated=result.get("alerts_generated", 0)
                )
            else:
                logger.warning(
                    "Delivery tracking internal endpoint returned no result",
                    tenant_id=tenant_id
                )

            return result

        except Exception as e:
            logger.error(
                "Error triggering delivery tracking via internal endpoint",
                tenant_id=tenant_id,
                error=str(e)
            )
            return None

    # ================================================================
    # INTERNAL AI INSIGHTS METHODS
    # ================================================================

    async def trigger_price_insights_internal(
        self,
        tenant_id: str
    ) -> Optional[Dict[str, Any]]:
        """
        Trigger price forecasting insights for a tenant (internal service use only).

        This method calls the internal endpoint which is protected by x-internal-service header.

        Args:
            tenant_id: Tenant ID to trigger insights for

        Returns:
            Dict with trigger results or None if failed
        """
        try:
            result = await self._make_request(
                method="POST",
                endpoint="procurement/internal/ml/generate-price-insights",
                tenant_id=tenant_id,
                data={"tenant_id": tenant_id},
                headers={"x-internal-service": "demo-session"}
            )

            if result:
                logger.info(
                    "Price insights triggered successfully via internal endpoint",
                    tenant_id=tenant_id,
                    insights_posted=result.get("insights_posted", 0)
                )
            else:
                logger.warning(
                    "Price insights internal endpoint returned no result",
                    tenant_id=tenant_id
                )

            return result

        except Exception as e:
            logger.error(
                "Error triggering price insights via internal endpoint",
                tenant_id=tenant_id,
                error=str(e)
            )
            return None


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