import time
from logging import getLogger
from threading import Thread
from uuid import uuid4

from enums.locations import Locations
from fastapi import HTTPException, APIRouter, Depends
from fastapi.responses import JSONResponse

from fudo import fudo
from models.sales import ItemWeb, OrderWeb
from models.items import Item, Order
from models.user import User
from services.fudo_service import add_product_to_fudo
from services.email_service import get_email_sender
import services.print_service as ps
from services.data_service import DataServiceFactory
from config.mails import PRINTER_DISCONNECTED_MAIL
from config.messages import ErrorResponse, SuccessResponse, UserResponse
from config.settings import DEVELOPMENT
from auth.security import get_current_user
from data.product_category import CAT_ITEMS
from utils.responses import error_response, success_response
from datetime import datetime

logger = getLogger(__name__)

# Data services initialization
user_data_service = DataServiceFactory.get_user_service()
product_data_service = DataServiceFactory.get_product_service()
sale_data_service = DataServiceFactory.get_sales_service()

# Global variables
printer_orders = []
order_router = APIRouter()
name_promo = "Shop"

@order_router.post("/send")
async def printer_order(order: OrderWeb, current_user: User = Depends(get_current_user)):
    """Process printer order"""
    logger.info(f"Printer order received from user {current_user.email} for table {order.table}")
    
    
    
    # Extract order data
    items = order.items
    table = order.table

    # Input validation
    if not items or not table:
        logger.warning(f"Invalid order data from user {current_user.email}: missing items or table")
        return error_response(message=ErrorResponse.MISSING_FIELDS, status_code=400)

    if not isinstance(table, int):
        logger.warning(f"Invalid table type from user {current_user.email}: {type(table)}")
       
        return error_response(message=ErrorResponse.INVALID_TABLE_TYPE, status_code=400)

    logger.info(f"Processing order for table {table} with {len(items)} items")



    # Get products data
    try:
        products = product_data_service.get_products([item.id for item in items])
        # Me aseguro de que los items y los productos esten en el mismo orden
        products = list(sorted(products, key=lambda x: x.id))
        items = list(sorted(items, key=lambda x: x.id))
        logger.info(f"Retrieved {len(products)} products from database")
        
        
    except Exception as e:
        error_msg = f"Error getting products: {e}"
        logger.error(error_msg)
        return error_response(message=error_msg, status_code=500)

    printers = {}
    
    for product in products:
        location = CAT_ITEMS[product.type or ""]
        if location.value not in printers:
            printers[location.value] = ps.get_status(location)

    # Printer status validation
    if not DEVELOPMENT:
        try:
            printer_status = [key for key, value in printers.items() if value == False]
            print(printer_status)
            if list(printer_status):
                logger.error(f"Printer is not connected. Order from user {current_user.email} cannot be processed.")
       
                
                # Send notification email to admins
                email_thread = Thread(
                    target=get_email_sender().send_email,
                    args=(
                        PRINTER_DISCONNECTED_MAIL["subject"].format(location=", ".join([loc for loc in printer_status])),
                        PRINTER_DISCONNECTED_MAIL["body"].format(location=", ".join([loc for loc in printer_status]), timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")), #type: ignore
                        ["erwinjacimino2003@gmail.com", "mompyn@gmail.com"
                        #  , "i.perez03@ufromail.cl", "marceloburkart94@gmail.com"
                         ]
                    ),
                    daemon=True
                )
                email_thread.start()
                
                
                return error_response(message=ErrorResponse.PRINTER_DISCONNECTED, status_code=424)
                
        except Exception as e:
            logger.error(f"Error checking printer status: {e}")
            return error_response(message=f"Error checking printer status: {e}", status_code=424)


    # Input validation
 
    # Add products to Fudo
    product_errors = []

    beers_for_promo = 0
    
    try:
        fudo.get_token()
        logger.info("Fudo token obtained successfully")
        
        for item, product in zip(items, products):
            try:
                # Si es dia de promo y es menos de las 8 pm
                if time.localtime().tm_wday + 1 == product.promo_day and product.promo_id and time.localtime().tm_hour < 20:
                    logger.info(f"Applying promotion for product {product.id} on table {table}")
                    fudo_product = add_product_to_fudo(product.promo_id, item.quantity, table)
                    
                #en caso contrario
                else:
                    if product.type == name_promo and current_user.name != "Guest":
                        beers_for_promo += item.quantity
                        logger.debug(f"Added {item.quantity} beers for promotion calculation")
                    
                    fudo_product = add_product_to_fudo(item.id, item.quantity, table)
                    
                    logger.info(f"Added product {item.id} to table {table} with quantity {item.quantity} in fudo")
                
                if not fudo_product: 
                    error_msg = f"Error adding product {item.id} to table {table}."
                    product_errors.append(error_msg)
                    logger.error(error_msg)
                   
                    
            except Exception as e:
                error_msg = f"Error processing product {item.id}: {e}"
                logger.error(error_msg)
                product_errors.append(error_msg)
                
                
    except Exception as e:
        error_msg = f"Error with Fudo integration: {e}"
        logger.error(error_msg)
        
        return error_response(message=error_msg, status_code=500)

    if product_errors:
        logger.error(f"Product errors occurred: {product_errors}")
        
        return error_response(error={"errors": product_errors}, message=ErrorResponse.PRODUCT_ADD_ERROR, status_code=424)


    
    # Get active sale
    try:
        active_sale_id = fudo.get_active_sale(fudo.get_table(table))
        if not active_sale_id:
            error_msg = f"No active sale found for table {table}"
            logger.error(error_msg)
            
            return error_response(message=error_msg, status_code=404)
            
        active_sale_id = active_sale_id['id']
        logger.info(f"Active sale found for table {table}: {active_sale_id}")
    except Exception as e:
        error_msg = f"Error retrieving active sale for table {table}: {e}"
        logger.error(error_msg)
        
        return error_response(message=error_msg, status_code=500)

    # Update user reward progress
    try:
        new_progress = current_user.reward_progress + beers_for_promo * 10
        user_data_service.set_reward_progress(current_user.id, new_progress)
        
        logger.info(f"Updated reward progress for user {current_user.email}: {current_user.reward_progress} -> {new_progress}")
        
        
    except Exception as e:
        error_msg = f"Error updating reward progress for user {current_user.id}: {e}"
        logger.error(error_msg)
        # Don't fail the order for this, just log it
        new_progress = current_user.reward_progress

    # Create sale record
    try:
        sale = sale_data_service.create(
            order.customerId,
            active_sale_id or uuid4().hex,
            order.totalAmount,
            order.table,
            [item.id for item in items],
            [item.quantity for item in items]
        )   
        
        if sale > 0:
            logger.info(f"Sale created successfully: ID {sale}")
        else:
            error_msg = "Failed to create sale record"
            logger.error(error_msg)
            return error_response(message=error_msg, status_code=500)
            
    except Exception as e:
        error_msg = f"Error creating sale record: {e}"
        logger.error(error_msg)
        
        return error_response(message=error_msg, status_code=500)

    # Print order
    try:
        print("items:")
        print(items)
        print("products:")
        print(products)
        pizza_items = [ Item(name=product.name, price=item.price, quantity=item.quantity, comment=item.comment) for item, product in zip(items, products) if CAT_ITEMS.get(product.type) == Locations.PIZZAS]#type: ignore
        burger_items = [ Item(name=product.name, price=item.price, quantity=item.quantity, comment=item.comment) for item, product in zip(items, products) if CAT_ITEMS.get(product.type) == Locations.BURGUER]#type: ignore
        bar_items = [ Item(name=product.name, price=item.price, quantity=item.quantity, comment=item.comment) for item, product in zip(items, products) if CAT_ITEMS.get(product.type) == Locations.BAR]#type: ignore
        coctelery_items = [ Item(name=product.name, price=item.price, quantity=item.quantity, comment=item.comment) for item, product in zip(items, products) if CAT_ITEMS.get(product.type) == Locations.COCTELERY]#type: ignore
        print("bar_items:")
        print(list(map(lambda x: x.model_dump(), bar_items)))

        if pizza_items:
            ps.print_order(Order(table=table, items=pizza_items, customerName=current_user.name, totalAmount=order.totalAmount, orderDate=order.orderDate), location=Locations.PIZZAS)
            logger.info(f"Order pizza printed successfully for table {table}")
        if burger_items:
            ps.print_order(Order(table=table, items=burger_items, customerName=current_user.name, totalAmount=order.totalAmount, orderDate=order.orderDate), location=Locations.BURGUER)
            logger.info(f"Order burger printed successfully for table {table}")
        if bar_items:
            ps.print_order(Order(table=table, items=bar_items, customerName=current_user.name, totalAmount=order.totalAmount, orderDate=order.orderDate), location=Locations.BAR)
            logger.info(f"Order bar printed successfully for table {table}")
        if coctelery_items:
            ps.print_order(Order(table=table, items=coctelery_items, customerName=current_user.name, totalAmount=order.totalAmount, orderDate=order.orderDate), location=Locations.COCTELERY)
            logger.info(f"Order coctelery printed successfully for table {table}")
         
        
        logger.info(f"Order printed successfully for table {table}")
        
        
    except Exception as e:
        error_msg = f"Error printing order for table {table}: {e}"
        logger.error(error_msg)
        return error_response(message=error_msg, status_code=500)  
        # Don't fail the order for print issues, just log it

    logger.info(f"Logging order for table {table} with sale ID {sale}, products= {[(product.name, item.quantity) for product, item in zip(products, items)]}")
        
    logger.info(f"Order processing completed successfully for table {table}, sale ID: {sale}")
    return success_response(data={"new_progress": new_progress}, message=SuccessResponse.ORDER_SUCCESS)

