from fastapi import APIRouter, Depends, HTTPException, status
from typing import List
from sqlalchemy.orm import Session
from .. import models, schemas, auth
from ..database import get_db
import json

router = APIRouter(
    prefix="/operations",
    tags=["Operations"]
)

@router.post("/check-in", response_model=schemas.Item)
def check_in_item(
    op: schemas.OperationCreate,
    db: Session = Depends(get_db),
    current_user: auth.TokenData = Depends(auth.get_current_user)
):
    """[C-01] Check-in item — only for authenticated users. [M-02] user_id from token."""
    if op.quantity <= 0:
        raise HTTPException(status_code=400, detail="Quantity must be greater than zero")

    item = db.query(models.Item).filter(models.Item.barcode == op.barcode).first()
    if not item:
        raise HTTPException(status_code=404, detail="Item not found. Register item first.")

    # Update quantity
    item.quantity += op.quantity

    # Create Mandatory Audit Log — [M-02] user_id from token
    item_snapshot = {
        "barcode": item.barcode,
        "name": item.name,
        "category": item.category,
        "part_number": item.part_number
    }

    audit = models.AuditLog(
        user_id=current_user.sub,
        action="CHECK_IN",
        target_item_id=item.id,
        target_item_name=item.name,
        target_item_pn=item.part_number,
        target_item_barcode=item.barcode,
        target_snapshot=json.dumps(item_snapshot),
        quantity_change=op.quantity
    )

    db.add(audit)
    db.commit()
    db.refresh(item)
    return item

@router.post("/check-out", response_model=schemas.Item)
def check_out_item(
    op: schemas.OperationCreate,
    db: Session = Depends(get_db),
    current_user: auth.TokenData = Depends(auth.get_current_user)
):
    """[C-01] Check-out item — only for authenticated users."""
    if op.quantity <= 0:
        raise HTTPException(status_code=400, detail="Quantity must be greater than zero")

    item = db.query(models.Item).filter(models.Item.barcode == op.barcode).first()
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    if item.quantity < op.quantity:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Insufficient stock")

    # Update quantity
    item.quantity -= op.quantity

    # Create Mandatory Audit Log
    item_snapshot = {
        "barcode": item.barcode,
        "name": item.name,
        "category": item.category,
        "part_number": item.part_number
    }

    audit = models.AuditLog(
        user_id=current_user.sub,
        action="CHECK_OUT",
        target_item_id=item.id,
        target_item_name=item.name,
        target_item_pn=item.part_number,
        target_item_barcode=item.barcode,
        target_snapshot=json.dumps(item_snapshot),
        quantity_change=-op.quantity
    )

    db.add(audit)
    db.commit()
    db.refresh(item)
    return item

@router.post("/trash", response_model=schemas.Item)
def trash_item(
    op: schemas.TrashOperationCreate,
    db: Session = Depends(get_db),
    current_user: auth.TokenData = Depends(auth.get_current_user)
):
    """[C-01] Trash item — only for authenticated users."""
    if op.quantity <= 0:
        raise HTTPException(status_code=400, detail="Quantity must be greater than zero")

    item = db.query(models.Item).filter(models.Item.barcode == op.barcode).first()
    if not item:
        raise HTTPException(status_code=404, detail="Item not found")

    if item.quantity < op.quantity:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Insufficient stock to trash")

    # Update quantity
    item.quantity -= op.quantity

    # Create Mandatory Audit Log with TRASH action and reason in details
    item_snapshot = {
        "barcode": item.barcode,
        "name": item.name,
        "category": item.category,
        "part_number": item.part_number
    }

    audit = models.AuditLog(
        user_id=current_user.sub,
        action="TRASH",
        target_item_id=item.id,
        target_item_name=item.name,
        target_item_pn=item.part_number,
        target_item_barcode=item.barcode,
        target_snapshot=json.dumps(item_snapshot),
        quantity_change=-op.quantity,
        details=op.reason
    )

    db.add(audit)
    db.commit()
    db.refresh(item)
    return item

@router.post("/bulk-check-out")
def bulk_check_out(
    bulk_op: schemas.BulkOperationCreate,
    db: Session = Depends(get_db),
    current_user: auth.TokenData = Depends(auth.get_current_user)
):
    """[C-01] Bulk check-out — only for authenticated users."""
    results = {"success": [], "errors": []}

    for op in bulk_op.items:
        try:
            item = db.query(models.Item).filter(models.Item.barcode == op.barcode).first()
            if not item:
                results["errors"].append({"barcode": op.barcode, "error": "Not found"})
                continue

            if item.quantity < op.quantity:
                results["errors"].append({"barcode": op.barcode, "error": f"Insufficient stock (Available: {item.quantity})"})
                continue

            # Update quantity
            item.quantity -= op.quantity

            # Log individual audit for this item
            item_snapshot = {
                "barcode": item.barcode,
                "name": item.name,
                "category": item.category,
                "part_number": item.part_number
            }

            audit = models.AuditLog(
                user_id=current_user.sub,
                action="BULK_CHECK_OUT",
                target_item_id=item.id,
                target_item_name=item.name,
                target_item_pn=item.part_number,
                target_item_barcode=item.barcode,
                target_snapshot=json.dumps(item_snapshot),
                quantity_change=-op.quantity
            )
            db.add(audit)
            results["success"].append({"barcode": op.barcode, "new_quantity": item.quantity})

        except Exception as e:
            results["errors"].append({"barcode": op.barcode, "error": str(e)})

    db.commit()
    return results

@router.post("/bulk-sync")
def bulk_sync(
    payload: schemas.SyncPayload,
    db: Session = Depends(get_db),
    current_user: auth.TokenData = Depends(auth.get_current_user)
):
    """[C-01] Bulk sync offline operations — only for authenticated users."""
    results = {"success": [], "errors": []}

    for op in payload.operations:
        try:
            # DEDUPLICATION CHECK: If this UUID already exists, skip it
            if op.uuid:
                existing = db.query(models.AuditLog).filter(models.AuditLog.uuid == op.uuid).first()
                if existing:
                    results["success"].append({"barcode": op.barcode, "type": op.type, "note": "Already synced"})
                    continue

            item = db.query(models.Item).filter(models.Item.barcode == op.barcode).first()
            if not item:
                results["errors"].append({"barcode": op.barcode, "error": "Item not found"})
                continue

            if op.type == "CHECK_IN":
                item.quantity += op.quantity
                change = op.quantity
            elif op.type == "CHECK_OUT" or op.type == "TRASH":
                if item.quantity < op.quantity:
                    results["errors"].append({"barcode": op.barcode, "error": f"Insufficient stock (Available: {item.quantity})"})
                    continue
                item.quantity -= op.quantity
                change = -op.quantity
            else:
                results["errors"].append({"barcode": op.barcode, "error": f"Invalid operation type: {op.type}"})
                continue

            # Log audit with original offline timestamp and UUID
            item_snapshot = {
                "barcode": item.barcode,
                "name": item.name,
                "category": item.category,
                "part_number": item.part_number
            }

            audit = models.AuditLog(
                user_id=current_user.sub,
                action=op.type,
                target_item_id=item.id,
                target_item_name=item.name,
                target_item_pn=item.part_number,
                target_item_barcode=item.barcode,
                target_snapshot=json.dumps(item_snapshot),
                quantity_change=change,
                timestamp=op.timestamp,
                uuid=op.uuid,
                details="Offline Synchronization"
            )
            db.add(audit)
            results["success"].append({"barcode": op.barcode, "type": op.type})

        except Exception as e:
            results["errors"].append({"barcode": op.barcode, "error": str(e)})

    db.commit()
    return results

@router.get("/logs", response_model=List[schemas.AuditLogResponse])
def get_logs(
    limit: int = 50,
    db: Session = Depends(get_db),
    current_user: auth.TokenData = Depends(auth.get_current_user)
):
    """[C-01] Audit logs list — only for authenticated users."""
    # Join with User to get the username directly
    logs_with_users = db.query(
        models.AuditLog.id,
        models.AuditLog.timestamp,
        models.AuditLog.user_id,
        models.User.username,
        models.AuditLog.action,
        models.AuditLog.target_item_id,
        models.AuditLog.target_item_name,
        models.AuditLog.target_item_pn,
        models.AuditLog.target_item_barcode,
        models.AuditLog.target_snapshot,
        models.AuditLog.quantity_change,
        models.AuditLog.details
    ).join(models.User, models.AuditLog.user_id == models.User.id).order_by(models.AuditLog.timestamp.desc()).limit(limit).all()

    # Mapper to dictionary for Pydantic
    return [
        {
            "id": l.id,
            "timestamp": l.timestamp,
            "user_id": l.user_id,
            "username": l.username,
            "action": l.action,
            "target_item_id": l.target_item_id,
            "target_item_name": l.target_item_name,
            "target_item_pn": l.target_item_pn,
            "target_item_barcode": l.target_item_barcode,
            "target_snapshot": l.target_snapshot,
            "quantity_change": l.quantity_change,
            "details": l.details
        } for l in logs_with_users
    ]
