"""
Internal Transfer Service for Inventory Management
Handles inventory ownership changes during internal transfers
"""

import logging
from typing import Dict, Any, List
from datetime import datetime
from decimal import Decimal
import uuid

from shared.clients.tenant_client import TenantServiceClient
from shared.clients.inventory_client import InventoryServiceClient

logger = logging.getLogger(__name__)


class InternalTransferInventoryService:
    """
    Service for handling inventory transfers during enterprise internal transfers
    """

    def __init__(
        self,
        tenant_client: TenantServiceClient,
        inventory_client: InventoryServiceClient
    ):
        self.tenant_client = tenant_client
        self.inventory_client = inventory_client

    async def process_internal_delivery(
        self,
        parent_tenant_id: str,
        child_tenant_id: str,
        shipment_items: List[Dict[str, Any]],
        shipment_id: str
    ) -> Dict[str, Any]:
        """
        Process inventory ownership transfer when internal shipment is delivered
        
        Args:
            parent_tenant_id: Source tenant (central production)
            child_tenant_id: Destination tenant (retail outlet)
            shipment_items: List of items being transferred with quantities
            shipment_id: ID of the shipment for reference
            
        Returns:
            Dict with transfer results
        """
        try:
            logger.info(
                "Processing internal inventory transfer",
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                shipment_id=shipment_id,
                item_count=len(shipment_items)
            )

            # Process each item in the shipment
            successful_transfers = []
            failed_transfers = []

            for item in shipment_items:
                product_id = item.get('product_id')
                quantity = Decimal(str(item.get('delivered_quantity', item.get('quantity', 0))))
                
                if not product_id or quantity <= 0:
                    logger.warning(
                        "Skipping invalid transfer item",
                        product_id=product_id,
                        quantity=quantity
                    )
                    continue

                try:
                    # Step 1: Deduct inventory from parent (central production)
                    parent_subtraction_result = await self._subtract_from_parent_inventory(
                        parent_tenant_id=parent_tenant_id,
                        product_id=product_id,
                        quantity=quantity,
                        shipment_id=shipment_id
                    )

                    # Step 2: Add inventory to child (retail outlet)
                    child_addition_result = await self._add_to_child_inventory(
                        child_tenant_id=child_tenant_id,
                        product_id=product_id,
                        quantity=quantity,
                        shipment_id=shipment_id
                    )

                    successful_transfers.append({
                        'product_id': product_id,
                        'quantity': float(quantity),
                        'parent_result': parent_subtraction_result,
                        'child_result': child_addition_result
                    })

                    logger.info(
                        "Internal inventory transfer completed",
                        product_id=product_id,
                        quantity=float(quantity),
                        parent_tenant_id=parent_tenant_id,
                        child_tenant_id=child_tenant_id
                    )

                except Exception as item_error:
                    logger.error(
                        "Failed to process inventory transfer for item",
                        product_id=product_id,
                        quantity=float(quantity),
                        error=str(item_error),
                        exc_info=True
                    )

                    failed_transfers.append({
                        'product_id': product_id,
                        'quantity': float(quantity),
                        'error': str(item_error)
                    })

            # Update shipment status in inventory records to reflect completed transfer
            await self._mark_shipment_as_completed_in_inventory(
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                shipment_id=shipment_id
            )

            total_transferred = sum(item['quantity'] for item in successful_transfers)
            
            result = {
                'shipment_id': shipment_id,
                'parent_tenant_id': parent_tenant_id,
                'child_tenant_id': child_tenant_id,
                'transfers_completed': len(successful_transfers),
                'transfers_failed': len(failed_transfers),
                'total_quantity_transferred': total_transferred,
                'successful_transfers': successful_transfers,
                'failed_transfers': failed_transfers,
                'status': 'completed' if failed_transfers == 0 else 'partial_success',
                'processed_at': datetime.utcnow().isoformat()
            }

            logger.info(
                "Internal inventory transfer processing completed",
                shipment_id=shipment_id,
                successfully_processed=len(successful_transfers),
                failed_count=len(failed_transfers)
            )

            return result

        except Exception as e:
            logger.error(
                "Error processing internal inventory transfer",
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                shipment_id=shipment_id,
                error=str(e),
                exc_info=True
            )
            raise

    async def _subtract_from_parent_inventory(
        self,
        parent_tenant_id: str,
        product_id: str,
        quantity: Decimal,
        shipment_id: str
    ) -> Dict[str, Any]:
        """
        Subtract inventory from parent tenant (central production)
        """
        try:
            # Check current inventory level in parent
            parent_stock = await self.inventory_client.get_product_stock(
                tenant_id=parent_tenant_id,
                product_id=product_id
            )

            current_stock = Decimal(str(parent_stock.get('available_quantity', 0)))
            
            if current_stock < quantity:
                raise ValueError(
                    f"Insufficient inventory in parent tenant {parent_tenant_id}. "
                    f"Required: {quantity}, Available: {current_stock}"
                )

            # Create stock movement record with negative quantity
            stock_movement_data = {
                'product_id': product_id,
                'movement_type': 'INTERNAL_TRANSFER_OUT',
                'quantity': float(-quantity),  # Negative for outbound
                'reference_type': 'internal_transfer',
                'reference_id': shipment_id,
                'source_tenant_id': parent_tenant_id,
                'destination_tenant_id': parent_tenant_id,  # Self-reference for tracking
                'notes': f'Shipment to child tenant #{shipment_id}'
            }

            # Execute the stock movement
            movement_result = await self.inventory_client.create_stock_movement(
                tenant_id=parent_tenant_id,
                movement_data=stock_movement_data
            )

            logger.info(
                "Inventory subtracted from parent",
                parent_tenant_id=parent_tenant_id,
                product_id=product_id,
                quantity=float(quantity),
                movement_id=movement_result.get('id')
            )

            return {
                'movement_id': movement_result.get('id'),
                'quantity_subtracted': float(quantity),
                'new_balance': float(current_stock - quantity),
                'status': 'success'
            }

        except Exception as e:
            logger.error(
                "Error subtracting from parent inventory",
                parent_tenant_id=parent_tenant_id,
                product_id=product_id,
                quantity=float(quantity),
                error=str(e)
            )
            raise

    async def _add_to_child_inventory(
        self,
        child_tenant_id: str,
        product_id: str,
        quantity: Decimal,
        shipment_id: str
    ) -> Dict[str, Any]:
        """
        Add inventory to child tenant (retail outlet)
        """
        try:
            # Create stock movement record with positive quantity
            stock_movement_data = {
                'product_id': product_id,
                'movement_type': 'INTERNAL_TRANSFER_IN',
                'quantity': float(quantity),  # Positive for inbound
                'reference_type': 'internal_transfer',
                'reference_id': shipment_id,
                'source_tenant_id': child_tenant_id,  # Self-reference from parent
                'destination_tenant_id': child_tenant_id,
                'notes': f'Internal transfer from parent tenant shipment #{shipment_id}'
            }

            # Execute the stock movement
            movement_result = await self.inventory_client.create_stock_movement(
                tenant_id=child_tenant_id,
                movement_data=stock_movement_data
            )

            logger.info(
                "Inventory added to child",
                child_tenant_id=child_tenant_id,
                product_id=product_id,
                quantity=float(quantity),
                movement_id=movement_result.get('id')
            )

            return {
                'movement_id': movement_result.get('id'),
                'quantity_added': float(quantity),
                'status': 'success'
            }

        except Exception as e:
            logger.error(
                "Error adding to child inventory",
                child_tenant_id=child_tenant_id,
                product_id=product_id,
                quantity=float(quantity),
                error=str(e)
            )
            raise

    async def _mark_shipment_as_completed_in_inventory(
        self,
        parent_tenant_id: str,
        child_tenant_id: str,
        shipment_id: str
    ):
        """
        Update inventory records to mark shipment as completed
        """
        try:
            # In a real implementation, this would update inventory tracking records
            # to reflect that the internal transfer is complete
            # For now, we'll just log that we're tracking this
            
            logger.info(
                "Marked internal transfer as completed in inventory tracking",
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                shipment_id=shipment_id
            )

        except Exception as e:
            logger.error(
                "Error updating inventory completion status",
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                shipment_id=shipment_id,
                error=str(e)
            )
            # This is not critical enough to fail the entire operation

    async def get_internal_transfer_history(
        self,
        parent_tenant_id: str,
        child_tenant_id: str = None,
        start_date: str = None,
        end_date: str = None,
        limit: int = 100
    ) -> List[Dict[str, Any]]:
        """
        Get history of internal inventory transfers
        
        Args:
            parent_tenant_id: Parent tenant ID
            child_tenant_id: Optional child tenant ID to filter by
            start_date: Optional start date filter
            end_date: Optional end date filter
            limit: Max results to return
            
        Returns:
            List of internal transfer records
        """
        try:
            # Build filter conditions
            filters = {
                'reference_type': 'internal_transfer'
            }
            
            if child_tenant_id:
                filters['destination_tenant_id'] = child_tenant_id
            if start_date:
                filters['created_after'] = start_date
            if end_date:
                filters['created_before'] = end_date

            # Query inventory movements for internal transfers
            parent_movements = await self.inventory_client.get_stock_movements(
                tenant_id=parent_tenant_id,
                filters=filters,
                limit=limit
            )

            # Filter for outbound transfers (negative values)
            outbound_transfers = [m for m in parent_movements if m.get('quantity', 0) < 0]

            # Also get inbound transfers for the children if specified
            all_transfers = outbound_transfers

            if child_tenant_id:
                child_movements = await self.inventory_client.get_stock_movements(
                    tenant_id=child_tenant_id,
                    filters=filters,
                    limit=limit
                )
                # Filter for inbound transfers (positive values)
                inbound_transfers = [m for m in child_movements if m.get('quantity', 0) > 0]
                all_transfers.extend(inbound_transfers)

            # Sort by creation date (most recent first)
            all_transfers.sort(key=lambda x: x.get('created_at', ''), reverse=True)

            return all_transfers[:limit]

        except Exception as e:
            logger.error(
                "Error getting internal transfer history",
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                error=str(e)
            )
            raise

    async def validate_internal_transfer_eligibility(
        self,
        parent_tenant_id: str,
        child_tenant_id: str,
        items: List[Dict[str, Any]]
    ) -> Dict[str, Any]:
        """
        Validate that internal transfer is possible (sufficient inventory, etc.)
        
        Args:
            parent_tenant_id: Parent tenant ID (supplier)
            child_tenant_id: Child tenant ID (recipient)
            items: List of items to transfer
            
        Returns:
            Dict with validation results
        """
        try:
            logger.info(
                "Validating internal transfer eligibility",
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                item_count=len(items)
            )

            validation_results = {
                'eligible': True,
                'errors': [],
                'warnings': [],
                'inventory_check': []
            }

            for item in items:
                product_id = item.get('product_id')
                quantity = Decimal(str(item.get('quantity', 0)))

                if quantity <= 0:
                    validation_results['errors'].append({
                        'product_id': product_id,
                        'error': 'Quantity must be greater than 0',
                        'quantity': float(quantity)
                    })
                    continue

                # Check if parent has sufficient inventory
                try:
                    parent_stock = await self.inventory_client.get_product_stock(
                        tenant_id=parent_tenant_id,
                        product_id=product_id
                    )

                    available_quantity = Decimal(str(parent_stock.get('available_quantity', 0)))

                    if available_quantity < quantity:
                        validation_results['errors'].append({
                            'product_id': product_id,
                            'error': 'Insufficient inventory in parent tenant',
                            'available': float(available_quantity),
                            'requested': float(quantity)
                        })
                    else:
                        validation_results['inventory_check'].append({
                            'product_id': product_id,
                            'available': float(available_quantity),
                            'requested': float(quantity),
                            'sufficient': True
                        })

                except Exception as stock_error:
                    logger.error(
                        "Error checking parent inventory for validation",
                        product_id=product_id,
                        error=str(stock_error)
                    )
                    validation_results['errors'].append({
                        'product_id': product_id,
                        'error': f'Error checking inventory: {str(stock_error)}'
                    })

            # Overall eligibility based on errors
            validation_results['eligible'] = len(validation_results['errors']) == 0

            logger.info(
                "Internal transfer validation completed",
                eligible=validation_results['eligible'],
                error_count=len(validation_results['errors'])
            )

            return validation_results

        except Exception as e:
            logger.error(
                "Error validating internal transfer eligibility",
                parent_tenant_id=parent_tenant_id,
                child_tenant_id=child_tenant_id,
                error=str(e)
            )
            raise