# services/suppliers/app/api/purchase_orders.py
"""
Purchase Order CRUD API endpoints (ATOMIC)
"""

from fastapi import APIRouter, Depends, HTTPException, Query, Path
from typing import List, Optional, Dict, Any
from uuid import UUID
import structlog

from sqlalchemy.orm import Session
from app.core.database import get_db
from app.services.purchase_order_service import PurchaseOrderService
from app.schemas.suppliers import (
    PurchaseOrderCreate, PurchaseOrderUpdate, PurchaseOrderResponse, PurchaseOrderSummary,
    PurchaseOrderSearchParams
)
from app.models.suppliers import PurchaseOrderStatus
from app.models import AuditLog
from shared.auth.decorators import get_current_user_dep
from shared.routing import RouteBuilder
from shared.auth.access_control import require_user_role
from shared.security import create_audit_logger, AuditSeverity, AuditAction

# Create route builder for consistent URL structure
route_builder = RouteBuilder('suppliers')


router = APIRouter(tags=["purchase-orders"])
logger = structlog.get_logger()
audit_logger = create_audit_logger("suppliers-service", AuditLog)


@router.post(route_builder.build_base_route("purchase-orders"), response_model=PurchaseOrderResponse)
@require_user_role(['admin', 'owner', 'member'])
async def create_purchase_order(
    po_data: PurchaseOrderCreate,
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Create a new purchase order"""
    # require_permissions(current_user, ["purchase_orders:create"])
    
    try:
        service = PurchaseOrderService(db)
        purchase_order = await service.create_purchase_order(
            tenant_id=current_user["tenant_id"],
            po_data=po_data,
            created_by=current_user["user_id"]
        )
        return PurchaseOrderResponse.from_orm(purchase_order)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error creating purchase order", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to create purchase order")


@router.get(route_builder.build_base_route("purchase-orders"), response_model=List[PurchaseOrderSummary])
async def list_purchase_orders(
    supplier_id: Optional[UUID] = Query(None, description="Filter by supplier ID"),
    status: Optional[str] = Query(None, description="Filter by status"),
    priority: Optional[str] = Query(None, description="Filter by priority"),
    date_from: Optional[str] = Query(None, description="Filter from date (YYYY-MM-DD)"),
    date_to: Optional[str] = Query(None, description="Filter to date (YYYY-MM-DD)"),
    search_term: Optional[str] = Query(None, description="Search term"),
    limit: int = Query(50, ge=1, le=1000, description="Number of results to return"),
    offset: int = Query(0, ge=0, description="Number of results to skip"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """List purchase orders with optional filters"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        from datetime import datetime
        
        # Parse date filters
        date_from_parsed = None
        date_to_parsed = None
        if date_from:
            try:
                date_from_parsed = datetime.fromisoformat(date_from)
            except ValueError:
                raise HTTPException(status_code=400, detail="Invalid date_from format")
        
        if date_to:
            try:
                date_to_parsed = datetime.fromisoformat(date_to)
            except ValueError:
                raise HTTPException(status_code=400, detail="Invalid date_to format")
        
        # Validate status
        status_enum = None
        if status:
            try:
                # Convert from PENDING_APPROVAL to pending_approval format
                status_value = status.lower()
                status_enum = PurchaseOrderStatus(status_value)
            except ValueError:
                raise HTTPException(status_code=400, detail="Invalid status")
        
        service = PurchaseOrderService(db)
        search_params = PurchaseOrderSearchParams(
            supplier_id=supplier_id,
            status=status_enum,
            priority=priority,
            date_from=date_from_parsed,
            date_to=date_to_parsed,
            search_term=search_term,
            limit=limit,
            offset=offset
        )
        
        orders = await service.search_purchase_orders(
            tenant_id=current_user["tenant_id"],
            search_params=search_params
        )

        # Convert to response with supplier names
        response = []
        for order in orders:
            order_dict = {
                "id": order.id,
                "po_number": order.po_number,
                "supplier_id": order.supplier_id,
                "supplier_name": order.supplier.name if order.supplier else None,
                "status": order.status,
                "priority": order.priority,
                "order_date": order.order_date,
                "required_delivery_date": order.required_delivery_date,
                "total_amount": order.total_amount,
                "currency": order.currency,
                "created_at": order.created_at
            }
            response.append(PurchaseOrderSummary(**order_dict))

        return response
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error listing purchase orders", error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve purchase orders")


@router.get(route_builder.build_resource_detail_route("purchase-orders", "po_id"), response_model=PurchaseOrderResponse)
async def get_purchase_order(
    po_id: UUID = Path(..., description="Purchase order ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Get purchase order by ID with items"""
    # require_permissions(current_user, ["purchase_orders:read"])
    
    try:
        service = PurchaseOrderService(db)
        purchase_order = await service.get_purchase_order(po_id)

        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")

        # Tenant access control is handled by the gateway
        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error getting purchase order", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to retrieve purchase order")


@router.put(route_builder.build_resource_detail_route("purchase-orders", "po_id"), response_model=PurchaseOrderResponse)
@require_user_role(['admin', 'owner', 'member'])
async def update_purchase_order(
    po_data: PurchaseOrderUpdate,
    po_id: UUID = Path(..., description="Purchase order ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Update purchase order information"""
    # require_permissions(current_user, ["purchase_orders:update"])

    try:
        service = PurchaseOrderService(db)

        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user["tenant_id"]:
            raise HTTPException(status_code=403, detail="Access denied")

        purchase_order = await service.update_purchase_order(
            po_id=po_id,
            po_data=po_data,
            updated_by=current_user["user_id"]
        )

        if not purchase_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")

        return PurchaseOrderResponse.from_orm(purchase_order)
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error("Error updating purchase order", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to update purchase order")


@router.delete(route_builder.build_resource_detail_route("purchase-orders", "po_id"))
@require_user_role(['admin', 'owner'])
async def delete_purchase_order(
    po_id: UUID = Path(..., description="Purchase order ID"),
    tenant_id: str = Path(..., description="Tenant ID"),
    current_user: Dict[str, Any] = Depends(get_current_user_dep),
    db: Session = Depends(get_db)
):
    """Delete purchase order (soft delete, Admin+ only)"""
    try:
        service = PurchaseOrderService(db)

        # Check order exists and belongs to tenant
        existing_order = await service.get_purchase_order(po_id)
        if not existing_order:
            raise HTTPException(status_code=404, detail="Purchase order not found")
        if existing_order.tenant_id != current_user["tenant_id"]:
            raise HTTPException(status_code=403, detail="Access denied")

        # Capture PO data before deletion
        po_data = {
            "po_number": existing_order.order_number,
            "supplier_id": str(existing_order.supplier_id),
            "status": existing_order.status.value if existing_order.status else None,
            "total_amount": float(existing_order.total_amount) if existing_order.total_amount else 0.0,
            "expected_delivery_date": existing_order.expected_delivery_date.isoformat() if existing_order.expected_delivery_date else None
        }

        # Delete purchase order (likely soft delete in service)
        success = await service.delete_purchase_order(po_id)
        if not success:
            raise HTTPException(status_code=404, detail="Purchase order not found")

        # Log audit event for purchase order deletion
        try:
            await audit_logger.log_deletion(
                db_session=db,
                tenant_id=tenant_id,
                user_id=current_user["user_id"],
                resource_type="purchase_order",
                resource_id=str(po_id),
                resource_data=po_data,
                description=f"Admin {current_user.get('email', 'unknown')} deleted purchase order {po_data['po_number']}",
                endpoint=f"/purchase-orders/{po_id}",
                method="DELETE"
            )
        except Exception as audit_error:
            logger.warning("Failed to log audit event", error=str(audit_error))

        logger.info("Deleted purchase order",
                   po_id=str(po_id),
                   tenant_id=tenant_id,
                   user_id=current_user["user_id"])

        return {"message": "Purchase order deleted successfully"}
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Error deleting purchase order", po_id=str(po_id), error=str(e))
        raise HTTPException(status_code=500, detail="Failed to delete purchase order")


