from app.services.base_service import BaseService
from sqlalchemy.orm import Session
from app.db.database import transaction
from app.schemas.file import FileInDB
from app.models.tcgplayer_products import TCGPlayerProduct, MTGJSONCard, MTGJSONSKU
from app.models.critical_error_log import CriticalErrorLog
from app.models.manabox_import_staging import ManaboxImportStaging
from typing import Dict, Any, Union, List
import csv
import logging
from datetime import datetime
import asyncio

logger = logging.getLogger(__name__)

class ManaboxService(BaseService):
    def __init__(self):
        super().__init__(None)

    async def process_manabox_csv(self, db: Session, bytes: bytes, metadata: Dict[str, Any], wait: bool = False) -> Union[bool, List[FileInDB]]:
        # save file 
        file = await self.file_service.save_file(
            db=db,
            file_data=bytes,
            filename=f"manabox_{datetime.now().strftime('%Y%m%d%H%M%S')}.csv",
            subdir="manabox",
            file_type="manabox",
            content_type="text/csv",
            metadata=metadata
        )
        
        # Create the background task
        task = asyncio.create_task(self._process_file_background(db, file))
        
        # If wait is True, wait for the task to complete and return the file
        if wait:
            await task
            return_value = await self.file_service.get_file(db, file.id)
            return [return_value] if return_value else []
            
        return True

    async def _process_file_background(self, db: Session, file: FileInDB):
        try:
            # Read the CSV file
            with open(file.path, 'r') as csv_file:
                reader = csv.DictReader(csv_file)
                # skip header row
                next(reader)
                for row in reader:
                    # match scryfall id to mtgjson scryfall id, make sure only one distinct tcgplayer id
                    mtg_json = db.query(MTGJSONCard).filter(MTGJSONCard.scryfall_id == row['Scryfall ID']).all()
                    # count distinct tcgplayer ids
                    cd_tcgplayer_ids = db.query(MTGJSONCard.tcgplayer_sku_id).filter(MTGJSONCard.scryfall_id == row['Scryfall ID']).distinct().count()
                    if cd_tcgplayer_ids != 1:
                        logger.error(f"Error: multiple TCGplayer IDs found for scryfall id: {row['Scryfall ID']} found {cd_tcgplayer_ids} ids expected 1")
                        with transaction(db):
                            critical_error_log = CriticalErrorLog(
                                error_message=f"Error: multiple TCGplayer IDs found for scryfall id: {row['Scryfall ID']} found {cd_tcgplayer_ids} ids expected 1"
                            )
                            db.add(critical_error_log)
                        continue
                    else:
                        mtg_json = mtg_json[0]
                    # get tcgplayer sku id from mtgjson skus
                    language = 'ENGLISH' if row['Language'] == 'en' else 'JAPANESE' if row['Language'] == 'ja' else None
                    if row['Foil'].lower() == 'etched':
                        printing = 'FOIL'
                        tcgplayer_sku = db.query(MTGJSONSKU).filter(MTGJSONSKU.tcgplayer_sku_id == mtg_json.tcgplayer_etched_sku_id).filter(MTGJSONSKU.condition == row['Condition'].replace('_', ' ').upper()).filter(MTGJSONSKU.printing == printing).filter(MTGJSONSKU.language == language).distinct().all()
                    else:
                        printing = 'FOIL' if row['Foil'].lower() == 'foil' else 'NON FOIL'
                        tcgplayer_sku = db.query(MTGJSONSKU).filter(MTGJSONSKU.tcgplayer_sku_id == mtg_json.tcgplayer_sku_id).filter(MTGJSONSKU.condition == row['Condition'].replace('_', ' ').upper()).filter(MTGJSONSKU.printing == printing).filter(MTGJSONSKU.language == language).distinct().all()
                    # count distinct tcgplayer skus
                    if len(tcgplayer_sku) == 0:
                        logger.error(f"Error: No TCGplayer SKU found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}")
                        with transaction(db):
                            critical_error_log = CriticalErrorLog(
                                error_message=f"Error: No TCGplayer SKU found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}"
                            )
                            db.add(critical_error_log)
                        continue
                    elif len(tcgplayer_sku) > 1:
                        logger.error(f"Error: {len(tcgplayer_sku)} TCGplayer SKUs found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}")
                        with transaction(db):
                            critical_error_log = CriticalErrorLog(
                                error_message=f"Error: {len(tcgplayer_sku)} TCGplayer SKUs found for mtgjson name: {mtg_json.name} condition: {row['Condition']} language: {language} printing: {printing}"
                            )
                            db.add(critical_error_log)
                        continue
                    else:
                        tcgplayer_sku = tcgplayer_sku[0]
                        # look up tcgplayer product data for sku
                        tcgplayer_product = db.query(TCGPlayerProduct).filter(TCGPlayerProduct.tcgplayer_product_id == tcgplayer_sku.tcgplayer_product_id).filter(TCGPlayerProduct.condition == row['Condition'].replace('_', ' ').upper()).filter(TCGPlayerProduct.language == language).filter(TCGPlayerProduct.printing == printing).first()

                        quantity = int(row['Quantity'])

                        with transaction(db):
                            manabox_import_staging = ManaboxImportStaging(
                                file_id=file.id,
                                product_id=tcgplayer_product.id,
                                quantity=quantity,
                                created_at=datetime.now(),
                                updated_at=datetime.now()
                            )
                            db.add(manabox_import_staging)
        except Exception as e:
            logger.error(f"Error processing file: {str(e)}")
            with transaction(db):
                critical_error_log = CriticalErrorLog(
                    error_message=f"Error processing file: {str(e)}"
                )
                db.add(critical_error_log)