# app/modules/inventory/services/inventory_transaction_service.py
"""
Inventory Transaction Service.

Provides query operations for inventory transaction history.
All transaction WRITES are handled by OrderInventoryService.
This service handles transaction READS for reporting and auditing.
"""

import logging
from sqlalchemy import func
from sqlalchemy.orm import Session

from app.modules.catalog.exceptions import ProductNotFoundException
from app.modules.orders.exceptions import OrderNotFoundException
from app.modules.inventory.models.inventory import Inventory
from app.modules.inventory.models.inventory_transaction import InventoryTransaction
from app.modules.orders.models import Order
from app.modules.catalog.models import Product

logger = logging.getLogger(__name__)


class InventoryTransactionService:
    """Service for querying inventory transaction history."""

    def get_vendor_transactions(
        self,
        db: Session,
        vendor_id: int,
        skip: int = 0,
        limit: int = 50,
        product_id: int | None = None,
        transaction_type: str | None = None,
    ) -> tuple[list[dict], int]:
        """
        Get inventory transactions for a vendor with optional filters.

        Args:
            db: Database session
            vendor_id: Vendor ID
            skip: Pagination offset
            limit: Pagination limit
            product_id: Optional product filter
            transaction_type: Optional transaction type filter

        Returns:
            Tuple of (transactions with product details, total count)
        """
        # Build query
        query = db.query(InventoryTransaction).filter(
            InventoryTransaction.vendor_id == vendor_id
        )

        # Apply filters
        if product_id:
            query = query.filter(InventoryTransaction.product_id == product_id)
        if transaction_type:
            query = query.filter(
                InventoryTransaction.transaction_type == transaction_type
            )

        # Get total count
        total = query.count()

        # Get transactions with pagination (newest first)
        transactions = (
            query.order_by(InventoryTransaction.created_at.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )

        # Build result with product details
        result = []
        for tx in transactions:
            product = db.query(Product).filter(Product.id == tx.product_id).first()
            product_title = None
            product_sku = None
            if product:
                product_sku = product.vendor_sku
                if product.marketplace_product:
                    product_title = product.marketplace_product.get_title()

            result.append(
                {
                    "id": tx.id,
                    "vendor_id": tx.vendor_id,
                    "product_id": tx.product_id,
                    "inventory_id": tx.inventory_id,
                    "transaction_type": (
                        tx.transaction_type.value if tx.transaction_type else None
                    ),
                    "quantity_change": tx.quantity_change,
                    "quantity_after": tx.quantity_after,
                    "reserved_after": tx.reserved_after,
                    "location": tx.location,
                    "warehouse": tx.warehouse,
                    "order_id": tx.order_id,
                    "order_number": tx.order_number,
                    "reason": tx.reason,
                    "created_by": tx.created_by,
                    "created_at": tx.created_at,
                    "product_title": product_title,
                    "product_sku": product_sku,
                }
            )

        return result, total

    def get_product_history(
        self,
        db: Session,
        vendor_id: int,
        product_id: int,
        limit: int = 50,
    ) -> dict:
        """
        Get transaction history for a specific product.

        Args:
            db: Database session
            vendor_id: Vendor ID
            product_id: Product ID
            limit: Max transactions to return

        Returns:
            Dict with product info, current inventory, and transactions

        Raises:
            ProductNotFoundException: If product not found or doesn't belong to vendor
        """
        # Get product details
        product = (
            db.query(Product)
            .filter(Product.id == product_id, Product.vendor_id == vendor_id)
            .first()
        )

        if not product:
            raise ProductNotFoundException(
                f"Product {product_id} not found in vendor catalog"
            )

        product_title = None
        product_sku = product.vendor_sku
        if product.marketplace_product:
            product_title = product.marketplace_product.get_title()

        # Get current inventory
        inventory = (
            db.query(Inventory)
            .filter(Inventory.product_id == product_id, Inventory.vendor_id == vendor_id)
            .first()
        )

        current_quantity = inventory.quantity if inventory else 0
        current_reserved = inventory.reserved_quantity if inventory else 0

        # Get transactions
        transactions = (
            db.query(InventoryTransaction)
            .filter(
                InventoryTransaction.vendor_id == vendor_id,
                InventoryTransaction.product_id == product_id,
            )
            .order_by(InventoryTransaction.created_at.desc())
            .limit(limit)
            .all()
        )

        total = (
            db.query(func.count(InventoryTransaction.id))
            .filter(
                InventoryTransaction.vendor_id == vendor_id,
                InventoryTransaction.product_id == product_id,
            )
            .scalar()
            or 0
        )

        return {
            "product_id": product_id,
            "product_title": product_title,
            "product_sku": product_sku,
            "current_quantity": current_quantity,
            "current_reserved": current_reserved,
            "transactions": [
                {
                    "id": tx.id,
                    "vendor_id": tx.vendor_id,
                    "product_id": tx.product_id,
                    "inventory_id": tx.inventory_id,
                    "transaction_type": (
                        tx.transaction_type.value if tx.transaction_type else None
                    ),
                    "quantity_change": tx.quantity_change,
                    "quantity_after": tx.quantity_after,
                    "reserved_after": tx.reserved_after,
                    "location": tx.location,
                    "warehouse": tx.warehouse,
                    "order_id": tx.order_id,
                    "order_number": tx.order_number,
                    "reason": tx.reason,
                    "created_by": tx.created_by,
                    "created_at": tx.created_at,
                }
                for tx in transactions
            ],
            "total": total,
        }

    def get_order_history(
        self,
        db: Session,
        vendor_id: int,
        order_id: int,
    ) -> dict:
        """
        Get all inventory transactions for a specific order.

        Args:
            db: Database session
            vendor_id: Vendor ID
            order_id: Order ID

        Returns:
            Dict with order info and transactions

        Raises:
            OrderNotFoundException: If order not found or doesn't belong to vendor
        """
        # Verify order belongs to vendor
        order = (
            db.query(Order)
            .filter(Order.id == order_id, Order.vendor_id == vendor_id)
            .first()
        )

        if not order:
            raise OrderNotFoundException(f"Order {order_id} not found")

        # Get transactions for this order
        transactions = (
            db.query(InventoryTransaction)
            .filter(InventoryTransaction.order_id == order_id)
            .order_by(InventoryTransaction.created_at.asc())
            .all()
        )

        # Build result with product details
        result = []
        for tx in transactions:
            product = db.query(Product).filter(Product.id == tx.product_id).first()
            product_title = None
            product_sku = None
            if product:
                product_sku = product.vendor_sku
                if product.marketplace_product:
                    product_title = product.marketplace_product.get_title()

            result.append(
                {
                    "id": tx.id,
                    "vendor_id": tx.vendor_id,
                    "product_id": tx.product_id,
                    "inventory_id": tx.inventory_id,
                    "transaction_type": (
                        tx.transaction_type.value if tx.transaction_type else None
                    ),
                    "quantity_change": tx.quantity_change,
                    "quantity_after": tx.quantity_after,
                    "reserved_after": tx.reserved_after,
                    "location": tx.location,
                    "warehouse": tx.warehouse,
                    "order_id": tx.order_id,
                    "order_number": tx.order_number,
                    "reason": tx.reason,
                    "created_by": tx.created_by,
                    "created_at": tx.created_at,
                    "product_title": product_title,
                    "product_sku": product_sku,
                }
            )

        return {
            "order_id": order_id,
            "order_number": order.order_number,
            "transactions": result,
        }


    # =========================================================================
    # Admin Methods (cross-vendor operations)
    # =========================================================================

    def get_all_transactions_admin(
        self,
        db: Session,
        skip: int = 0,
        limit: int = 50,
        vendor_id: int | None = None,
        product_id: int | None = None,
        transaction_type: str | None = None,
        order_id: int | None = None,
    ) -> tuple[list[dict], int]:
        """
        Get inventory transactions across all vendors (admin only).

        Args:
            db: Database session
            skip: Pagination offset
            limit: Pagination limit
            vendor_id: Optional vendor filter
            product_id: Optional product filter
            transaction_type: Optional transaction type filter
            order_id: Optional order filter

        Returns:
            Tuple of (transactions with details, total count)
        """
        from app.modules.tenancy.models import Vendor

        # Build query
        query = db.query(InventoryTransaction)

        # Apply filters
        if vendor_id:
            query = query.filter(InventoryTransaction.vendor_id == vendor_id)
        if product_id:
            query = query.filter(InventoryTransaction.product_id == product_id)
        if transaction_type:
            query = query.filter(
                InventoryTransaction.transaction_type == transaction_type
            )
        if order_id:
            query = query.filter(InventoryTransaction.order_id == order_id)

        # Get total count
        total = query.count()

        # Get transactions with pagination (newest first)
        transactions = (
            query.order_by(InventoryTransaction.created_at.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )

        # Build result with vendor and product details
        result = []
        for tx in transactions:
            vendor = db.query(Vendor).filter(Vendor.id == tx.vendor_id).first()
            product = db.query(Product).filter(Product.id == tx.product_id).first()

            product_title = None
            product_sku = None
            if product:
                product_sku = product.vendor_sku
                if product.marketplace_product:
                    product_title = product.marketplace_product.get_title()

            result.append(
                {
                    "id": tx.id,
                    "vendor_id": tx.vendor_id,
                    "vendor_name": vendor.name if vendor else None,
                    "vendor_code": vendor.vendor_code if vendor else None,
                    "product_id": tx.product_id,
                    "inventory_id": tx.inventory_id,
                    "transaction_type": (
                        tx.transaction_type.value if tx.transaction_type else None
                    ),
                    "quantity_change": tx.quantity_change,
                    "quantity_after": tx.quantity_after,
                    "reserved_after": tx.reserved_after,
                    "location": tx.location,
                    "warehouse": tx.warehouse,
                    "order_id": tx.order_id,
                    "order_number": tx.order_number,
                    "reason": tx.reason,
                    "created_by": tx.created_by,
                    "created_at": tx.created_at,
                    "product_title": product_title,
                    "product_sku": product_sku,
                }
            )

        return result, total

    def get_transaction_stats_admin(self, db: Session) -> dict:
        """
        Get transaction statistics across the platform (admin only).

        Returns:
            Dict with transaction counts by type
        """
        from sqlalchemy import func as sql_func

        # Count by transaction type
        type_counts = (
            db.query(
                InventoryTransaction.transaction_type,
                sql_func.count(InventoryTransaction.id).label("count"),
            )
            .group_by(InventoryTransaction.transaction_type)
            .all()
        )

        # Total transactions
        total = db.query(sql_func.count(InventoryTransaction.id)).scalar() or 0

        # Transactions today
        from datetime import UTC, datetime, timedelta

        today_start = datetime.now(UTC).replace(hour=0, minute=0, second=0, microsecond=0)
        today_count = (
            db.query(sql_func.count(InventoryTransaction.id))
            .filter(InventoryTransaction.created_at >= today_start)
            .scalar()
            or 0
        )

        return {
            "total_transactions": total,
            "transactions_today": today_count,
            "by_type": {tc.transaction_type.value: tc.count for tc in type_counts},
        }


# Create service instance
inventory_transaction_service = InventoryTransactionService()
