from typing import Optional, List, Dict
import csv
import io
import os
import json
from datetime import datetime
from sqlalchemy.orm import Session
from app.db.database import transaction
from app.models.inventory import Inventory
from app.models.tcgplayer_product import TCGPlayerProduct
from app.services.inventory_service import InventoryService

class FileProcessingService:
    def __init__(self, cache_dir: str = "app/data/cache/tcgplayer"):
        self.cache_dir = cache_dir
        self.inventory_service = InventoryService()
        os.makedirs(cache_dir, exist_ok=True)

    def _get_cache_path(self, filename: str) -> str:
        return os.path.join(self.cache_dir, filename)

    async def _cache_export(self, file_bytes: bytes, export_type: str):
        cache_path = self._get_cache_path(f"{export_type}_export.csv")
        with open(cache_path, 'wb') as f:
            f.write(file_bytes)

    async def _load_cached_export(self, export_type: str) -> Optional[bytes]:
        cache_path = self._get_cache_path(f"{export_type}_export.csv")
        if os.path.exists(cache_path):
            with open(cache_path, 'rb') as f:
                return f.read()
        return None

    async def process_tcgplayer_export(self, db: Session, file_bytes: bytes, export_type: str = "live", use_cache: bool = False) -> dict:
        """
        Process a TCGPlayer export file and load it into the inventory table.
        
        Args:
            db: Database session
            file_bytes: The downloaded file content as bytes
            export_type: Type of export (staged, live, pricing)
            use_cache: Whether to use cached export file for development
            
        Returns:
            dict: Processing statistics
        """
        stats = {
            "total_rows": 0,
            "processed_rows": 0,
            "errors": 0,
            "error_messages": []
        }
        
        try:
            # For development, use cached file if available
            if use_cache:
                cached_bytes = await self._load_cached_export(export_type)
                if cached_bytes:
                    file_bytes = cached_bytes
                else:
                    await self._cache_export(file_bytes, export_type)
            
            # Convert bytes to string and create a file-like object
            file_content = file_bytes.decode('utf-8')
            file_like = io.StringIO(file_content)
            
            # Read CSV file
            csv_reader = csv.DictReader(file_like)
            
            with transaction(db):
                for row in csv_reader:
                    stats["total_rows"] += 1
                    try:
                        # Process each row and create/update inventory item in database
                        inventory_data = self._map_tcgplayer_row_to_inventory(row)
                        tcgplayer_id = inventory_data["tcgplayer_id"]
                        
                        # Check if inventory item already exists
                        existing_item = self.inventory_service.get_by_tcgplayer_id(db, tcgplayer_id)
                        
                        # Find matching TCGPlayer product
                        product_id = int(tcgplayer_id) if tcgplayer_id.isdigit() else None
                        if product_id:
                            tcg_product = db.query(TCGPlayerProduct).filter(TCGPlayerProduct.product_id == product_id).first()
                            if tcg_product:
                                # Update inventory data with product information if available
                                inventory_data.update({
                                    "product_name": tcg_product.name,
                                    "photo_url": tcg_product.image_url,
                                    "rarity": tcg_product.ext_rarity,
                                    "number": tcg_product.ext_number
                                })
                        
                        if existing_item:
                            # Update existing item
                            self.inventory_service.update(db, existing_item, inventory_data)
                        else:
                            # Create new item
                            self.inventory_service.create(db, inventory_data)
                            
                        stats["processed_rows"] += 1
                    except Exception as e:
                        stats["errors"] += 1
                        stats["error_messages"].append(f"Error processing row {stats['total_rows']}: {str(e)}")
                        
            return stats
            
        except Exception as e:
            raise Exception(f"Failed to process TCGPlayer export: {str(e)}")

    def _map_tcgplayer_row_to_inventory(self, row: dict) -> dict:
        """
        Map TCGPlayer export row to inventory model fields.
        """
        def safe_float(value: str) -> float:
            """Convert string to float, returning 0.0 for empty strings or invalid values"""
            try:
                return float(value) if value else 0.0
            except ValueError:
                return 0.0

        def safe_int(value: str) -> int:
            """Convert string to int, returning 0 for empty strings or invalid values"""
            try:
                return int(value) if value else 0
            except ValueError:
                return 0

        return {
            "tcgplayer_id": row.get("TCGplayer Id", ""),
            "product_line": row.get("Product Line", ""),
            "set_name": row.get("Set Name", ""),
            "product_name": row.get("Product Name", ""),
            "title": row.get("Title", ""),
            "number": row.get("Number", ""),
            "rarity": row.get("Rarity", ""),
            "condition": row.get("Condition", ""),
            "tcg_market_price": safe_float(row.get("TCG Market Price", "")),
            "tcg_direct_low": safe_float(row.get("TCG Direct Low", "")),
            "tcg_low_price_with_shipping": safe_float(row.get("TCG Low Price With Shipping", "")),
            "tcg_low_price": safe_float(row.get("TCG Low Price", "")),
            "total_quantity": safe_int(row.get("Total Quantity", "")),
            "add_to_quantity": safe_int(row.get("Add to Quantity", "")),
            "tcg_marketplace_price": safe_float(row.get("TCG Marketplace Price", "")),
            "photo_url": row.get("Photo URL", "")
        } 