from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Request, BackgroundTasks from fastapi.responses import StreamingResponse from sqlalchemy.orm import Session from typing import Dict, Any, List, Optional from db.database import get_db from services.upload import UploadService from services.box import BoxService from services.tcgplayer import TCGPlayerService from services.data import DataService from services.file import FileService from services.product import ProductService from services.task import TaskService from schemas.file import FileSchema, CreateFileRequest, CreateFileResponse, GetFileResponse, DeleteFileResponse, GetFileQueryParams from schemas.box import CreateBoxResponse, CreateBoxRequestData from dependencies import get_data_service, get_upload_service, get_tcgplayer_service, get_box_service, get_create_file_metadata, get_file_service, get_product_service, get_task_service import logging logger = logging.getLogger(__name__) router = APIRouter(prefix="/api", tags=["cards"]) MAX_FILE_SIZE = 1024 * 1024 * 100 # 100 MB ## GIGA FOR REAL ## FILE ## CREATE @router.post( "/files", response_model=CreateFileResponse, status_code=201 ) @router.post( "/files", response_model=CreateFileResponse, status_code=201 ) async def create_file( background_tasks: BackgroundTasks, file: UploadFile = File(...), metadata: CreateFileRequest = Depends(get_create_file_metadata), file_service: FileService = Depends(get_file_service), task_service: TaskService = Depends(get_task_service) ): try: # Validate file size before reading if not file.filename: raise HTTPException(status_code=400, detail="No filename provided") # File size check content = await file.read() if len(content) > MAX_FILE_SIZE: raise HTTPException(status_code=413, detail="File too large") logger.debug(f"File received: {file.filename}") logger.debug(f"Metadata: {metadata}") # ADD FILENAME TO METADATA if not metadata.filename: metadata.filename = file.filename # VALIDATE FILE if not file_service.validate_file(content, metadata): raise HTTPException(status_code=400, detail="Invalid file content") # STORE FILE created_file = file_service.create_file(content, metadata) # Close file after processing await file.close() # handle manabox file background task if metadata.source == 'manabox': background_tasks.add_task(task_service.process_manabox_file, created_file) return CreateFileResponse( status_code=201, success=True, files=[FileSchema.from_orm(created_file)] # Changed to return list ) except HTTPException as http_ex: await file.close() raise http_ex except Exception as e: await file.close() logger.error(f"File upload failed: {str(e)}") raise HTTPException( status_code=500, detail="Internal server error occurred during file upload" ) ## FILE ## GET @router.get("/files/{file_id:path}", response_model=GetFileResponse) @router.get("/files", response_model=GetFileResponse) async def get_file( file_id: Optional[str] = None, query: GetFileQueryParams = Depends(), file_service: FileService = Depends(get_file_service) ): """ Get file(s) by optional ID and/or status. If file_id is provided, returns that specific file. If status is provided, returns all files with that status. If neither is provided, returns all files. """ try: if file_id: # Get specific file by ID file = file_service.get_file(file_id) return GetFileResponse( status_code=200, success=True, files=[FileSchema.from_orm(file)] ) else: # Get multiple files with optional status filter files = file_service.get_files(status=query.status) return GetFileResponse( status_code=200, success=True, files=[FileSchema.from_orm(f) for f in files] ) except Exception as e: logger.error(f"Get file(s) failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) ## DELETE @router.delete("/files/{file_id}", response_model=DeleteFileResponse) async def delete_file( file_id: str, file_service: FileService = Depends(get_file_service) ): try: file = file_service.delete_file(file_id) return DeleteFileResponse( status_code=200, success=True, files=[FileSchema.from_orm(file)] ) except Exception as e: logger.error(f"Delete file failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) # FILE """ @router.post("/file/uploadManabox", response_model=FileUploadResponse) async def upload_file( background_tasks: BackgroundTasks, file: UploadFile = File(...), file_service: FileService = Depends(get_file_service), product_service: ProductService = Depends(get_product_service), metadata: FileMetadata = Depends(get_file_metadata)) -> FileUploadResponse: try: content = await file.read() metadata.service = 'product' result = file_service.upload_file(content, file.filename, metadata) background_tasks.add_task(product_service.bg_process_manabox_file, result.id) return result except Exception as e: logger.error(f"File upload failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.get("/file/getPreparedFiles", response_model=GetPreparedFilesResponse) async def get_prepared_files(file_service: FileService = Depends(get_file_service)) -> GetPreparedFilesResponse: try: response = file_service.get_prepared_files() return response except Exception as e: logger.error(f"Get prepared files failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.post("/file/deleteFile", response_model=FileDeleteResponse) async def delete_file(file_id: str, file_service: FileService = Depends(get_file_service)) -> FileDeleteResponse: try: response = file_service.delete_file(file_id) return response except Exception as e: logger.error(f"Delete file failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.post("/box/createBox", response_model=CreateBoxResponse) async def create_box(file_ids: list[str], create_box_data: CreateBoxRequestData, box_service: BoxService = Depends(get_box_service)) -> CreateBoxResponse: try: create_box_data = create_box_data.dict() response = box_service.create_box(create_box_data, file_ids) return response except Exception as e: logger.error(f"Create box failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) """ ## all old below @router.post("/upload/manabox", response_model=dict) async def upload_manabox( background_tasks: BackgroundTasks, upload_service: UploadService = Depends(get_upload_service), data_service: DataService = Depends(get_data_service), file: UploadFile = File(...) ) -> dict: """ Upload endpoint for Manabox CSV files """ try: logger.info(f"file received: {file.filename}") # Read the file content content = await file.read() filename = file.filename file_size = len(content) file_size_kb = file_size / 1024 if not content: logger.error("Empty file content") raise HTTPException(status_code=400, detail="Empty file content") # You might want to validate it's a CSV file if not file.filename.endswith('.csv'): logger.error("File must be a CSV") raise HTTPException(status_code=400, detail="File must be a CSV") result = upload_service.process_manabox_upload(content, filename, file_size_kb) background_tasks.add_task(data_service.bg_set_manabox_tcg_relationship, upload_id=result[1]) return result[0] except Exception as e: logger.error(f"Manabox upload failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.post("/createBox", response_model=dict) async def create_box( upload_id: str, box_service: BoxService = Depends(get_box_service) ) -> dict: try: result = box_service.convert_upload_to_boxes(upload_id) except Exception as e: logger.error(f"Box creation failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) return result @router.post("/deleteBox", response_model=dict) async def delete_box( box_id: str, box_service: BoxService = Depends(get_box_service) ) -> dict: try: result = box_service.delete_box(box_id) except Exception as e: logger.error(f"Box deletion failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) return result @router.post("/tcgplayer/add/box/{box_id}", response_model=dict) async def add_box(box_id: str = None, tcgplayer_service: TCGPlayerService = Depends(get_tcgplayer_service)): try: csv_content = tcgplayer_service.add_to_tcgplayer(box_id) return StreamingResponse( iter([csv_content]), media_type="text/csv", headers={"Content-Disposition": "attachment; filename=add_to_tcgplayer.csv"} ) except Exception as e: logger.error(f"Box add failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.post("/tcgplayer/update/box/{box_id}", response_model=dict) async def update_box(box_id: int = None): """asdf""" pass @router.post("/tcgplayer/updateInventory", response_model=dict) async def update_inventory( background_tasks: BackgroundTasks, tcgplayer_service: TCGPlayerService = Depends(get_tcgplayer_service), data_service: DataService = Depends(get_data_service)): try: result = tcgplayer_service.update_inventory('live') export_id = result['export_id'] background_tasks.add_task(data_service.bg_set_tcg_inventory_product_relationship, export_id) return result except Exception as e: logger.error(f"Inventory update failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.post("/tcgplayer/updatePricing", response_model=dict) async def update_inventory( tcgplayer_service: TCGPlayerService = Depends(get_tcgplayer_service), group_ids: Dict = None): try: result = tcgplayer_service.update_pricing(group_ids) return result except Exception as e: logger.error(f"Pricing update failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.post("/tcgplayer/updatePricingAll", response_model=dict) async def update_inventory(tcgplayer_service: TCGPlayerService = Depends(get_tcgplayer_service)): try: result = tcgplayer_service.update_pricing_all() return result except Exception as e: logger.error(f"Pricing update failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) @router.get("/tcgplayer/createLiveInventoryPricingUpdateFile") async def create_inventory_import( tcgplayer_service: TCGPlayerService = Depends(get_tcgplayer_service) ): try: csv_content = tcgplayer_service.get_live_inventory_pricing_update_csv() return StreamingResponse( iter([csv_content]), media_type="text/csv", headers={"Content-Disposition": "attachment; filename=inventory_pricing_update.csv"} ) except Exception as e: logger.error(f"Inventory import creation failed: {str(e)}") raise HTTPException(status_code=400, detail=str(e))