#!/usr/bin/env python3
import argparse
import mysql.connector
from datetime import datetime
from time import sleep
import requests
import boto3
import zipfile
import io
from io import BytesIO
import os
import sys
import math
import qrcode
from PIL import Image
import logging
from botocore.exceptions import NoCredentialsError, ClientError
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager



# Configuration - You'll need to set these
API_TOKEN = "586|ZSiIeT0FOxNzYEAn8kCZGvzHedLKkwqyo3xsp69k03eea1a7"
API_URL = "https://app.buildagangsheet.com/api/v1/design/"
S3_BUCKET = "dtfbucket"
db_config = {
    "host": "localhost",
    "user": "upload15_uploadtransfers01",
    "password": "2!oum10ZDS",
    "database": "upload15_uploadtransfers01"
}

# Initialize S3 client
s3_client = boto3.client('s3')
Image.MAX_IMAGE_PIXELS = None

# Configure logging with more detailed format
logging.basicConfig(
    level=logging.INFO, 
    format='%(asctime)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s',
    handlers=[
        logging.FileHandler("processingfile.log", mode="a"),
        logging.StreamHandler(sys.stdout)  # Also log to console
    ]
)
logger = logging.getLogger(__name__)

class ImageProcessor:
    def __init__(self):
        logger.info("ImageProcessor initialized")
    
    def text_to_image(self, text, target_width=400):
        """Convert text to image using matplotlib."""
        logger.info(f"Converting text to image: '{text[:50]}...' (target_width: {target_width})")
        
        try:
            # Set up the figure with white background
            fig, ax = plt.subplots(figsize=(target_width/100, 2), facecolor='white')
            ax.set_facecolor('white')
            logger.debug(f"Figure created with size: {target_width/100} x 2")
            
            # Remove axes and margins
            ax.set_xlim(0, 1)
            ax.set_ylim(0, 1)
            ax.axis('off')
            
            # Try to find a good monospace font
            try:
                # Look for common monospace fonts
                font_names = ['DejaVu Sans Mono', 'Courier New', 'Monaco', 'Consolas', 'Liberation Mono']
                font_prop = None
                
                for font_name in font_names:
                    try:
                        font_prop = font_manager.FontProperties(family=font_name, weight='normal')
                        logger.debug(f"Successfully loaded font: {font_name}")
                        break
                    except Exception as e:
                        logger.debug(f"Failed to load font {font_name}: {e}")
                        continue
                
                if font_prop is None:
                    font_prop = font_manager.FontProperties(family='monospace')
                    logger.debug("Using fallback monospace font")
                    
            except Exception as e:
                logger.warning(f"Font loading failed, using default: {e}")
                font_prop = font_manager.FontProperties(family='monospace')
            
            # Start with a large font size and work down
            target_width_ratio = 0.9  # Use 90% of the width
            targetrange = 100 if target_width < 400 else 200
            final_font_size = None
            
            logger.debug(f"Finding optimal font size (range: {targetrange} to 10)")
            for font_size in range(targetrange, 10, -2):  # Start big, work down
                # Create temporary text to measure
                temp_text = ax.text(0.5, 0.5, text, fontproperties=font_prop, 
                                   fontsize=font_size, ha='center', va='center',
                                   color='black', transform=ax.transAxes)
                
                # Get the text width in figure coordinates
                fig.canvas.draw()
                bbox = temp_text.get_window_extent(renderer=fig.canvas.get_renderer())
                text_width_inches = bbox.width / fig.dpi
                fig_width_inches = fig.get_figwidth()
                width_ratio = text_width_inches / fig_width_inches
                
                # Remove the temporary text
                temp_text.remove()
                
                logger.debug(f"Font size {font_size}: width_ratio = {width_ratio:.3f}")
                
                # If text fits within our target, use this font size
                if width_ratio <= target_width_ratio:
                    final_font_size = font_size
                    logger.debug(f"Optimal font size found: {font_size}")
                    break
            
            if final_font_size is None:
                final_font_size = 12  # Fallback
                logger.warning(f"No optimal font size found, using fallback: {final_font_size}")
            
            # Create the final text with the optimal font size
            final_text = ax.text(0.5, 0.5, text, fontproperties=font_prop, 
                                fontsize=final_font_size, ha='center', va='center',
                                color='black', transform=ax.transAxes)
            
            # Calculate dynamic height based on text
            fig.canvas.draw()
            bbox = final_text.get_window_extent(renderer=fig.canvas.get_renderer())
            text_height_inches = bbox.height / fig.dpi
            
            # Add minimal padding and adjust figure height
            padding = 0.2  # inches
            new_height = text_height_inches + (padding * 2)
            fig.set_figheight(new_height)
            logger.debug(f"Adjusted figure height to: {new_height} inches")
            
            # Save to buffer instead of file
            buffer = BytesIO()
            plt.savefig(buffer, format='png', dpi=100, bbox_inches='tight',
                        pad_inches=0.05, facecolor='white', edgecolor='none')
            plt.close()
            buffer.seek(0)
            
            buffer_size = len(buffer.getvalue())
            logger.info(f"Text image created successfully (size: {buffer_size} bytes)")
            return buffer.getvalue()
            
        except Exception as e:
            logger.error(f"Failed to create text image: {e}")
            return None
    def add_qr_code_to_image_test(self, image_bytes, qr_content, image_format='PNG', product_id=-1, dpinfo=False):
        logger.info(f"Adding QR code to image (content: '{qr_content}', product_id: {product_id})")
        try:
            original_image = Image.open(BytesIO(image_bytes))
            logger.debug(f"Original image loaded: {original_image.size} ({original_image.mode})")
            
            dpi_info = original_image.info.get("dpi")
            logger.debug(f"Original DPI info: {dpi_info}")
            
            if dpi_info and dpi_info[0] and dpinfo is True:
                dpi_value = math.floor(dpi_info[0] + 0.5)
            else:
                dpi_value = 300
            
            logger.debug(f"Using DPI value: {dpi_value}")
            
            original_width, original_height = original_image.size
            logger.debug(f"Original dimensions: {original_width} x {original_height}")
            
            qr_size = 300
            if original_width < 300:
                qr_size = original_width
                logger.debug(f"Adjusted QR size to match image width: {qr_size}")
            
            if product_id == 31981:
                padded_qr_height = qr_size
            else:
                padded_qr_height = 2 * qr_size
            
            logger.debug(f"QR dimensions: {qr_size} x {qr_size}, padded height: {padded_qr_height}")
            
            if product_id == 31981:
                margin_height = padded_qr_height + 50
            else:
                margin_height = padded_qr_height + 20
            
            logger.debug(f"Margin height: {margin_height}")
            
            # Generate QR code
            logger.debug("Generating QR code...")
            qr = qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_L,
                box_size=10,
                border=4,
            )
            qr.add_data(qr_content)
            qr.make(fit=True)
            
            qr_image = qr.make_image(fill_color="black", back_color="white")
            qr_image = qr_image.resize((qr_size, qr_size), Image.Resampling.LANCZOS)
            logger.debug(f"QR code generated and resized to: {qr_image.size}")
            
            # Always create transparent padded QR image
            padded_qr_image = Image.new('RGBA', (qr_size, padded_qr_height), (0, 0, 0, 0))
            logger.debug(f"Created transparent padded QR container: {padded_qr_image.size}")
            
            # Make QR background transparent
            qr_rgba = Image.new('RGBA', qr_image.size, (255, 255, 255, 255))
            qr_rgba.paste(qr_image, (0, 0))
            qr_data = qr_rgba.getdata()
            new_qr_data = [(255, 255, 255, 0) if r > 200 and g > 200 and b > 200 else (r, g, b, a) for r, g, b, a in qr_data]
            qr_rgba.putdata(new_qr_data)
            logger.debug("Made QR background transparent")
            
            qr_y_in_padded = padded_qr_height - qr_size
            padded_qr_image.paste(qr_rgba, (0, qr_y_in_padded), qr_rgba)
            logger.debug(f"Pasted QR at position: (0, {qr_y_in_padded})")

            # Fetch and process logo
            logo_img = None
            logo_height = 0
            logo_padding = 10
            
            try:
                import requests
                logo_url = "https://uploadtransfers.com/wp-content/uploads/2021/03/main-logo-e1648138042828.png"
                response = requests.get(logo_url, timeout=5)
                
                if response.status_code == 200:
                    logo_img = Image.open(BytesIO(response.content))
                    if logo_img.mode != 'RGBA':
                        logo_img = logo_img.convert('RGBA')
                    
                    max_logo_width = min(qr_size, int(original_width * 0.8))
                    aspect_ratio = logo_img.height / logo_img.width
                    new_logo_width = max_logo_width
                    new_logo_height = int(new_logo_width * aspect_ratio)
                    logo_img = logo_img.resize((new_logo_width, new_logo_height), Image.Resampling.LANCZOS)
                    logo_height = new_logo_height
            except Exception as e:
                print(f"Failed to fetch/process logo: {e}")
                logo_img = None
                logo_height = 0
            
            # Text generation
            used_text = qr_content
            if '.' in qr_content:
                used_text = qr_content.split('.')[0]
                logger.debug(f"Extracted text for image: '{used_text}' from '{qr_content}'")
            
            target_width = 400 if original_width < 300 else qr_size
            logger.debug(f"Target text width: {target_width}")
            
            try:
                logger.debug("Generating text image...")
                text_img_bytes = self.text_to_image(used_text, target_width)
                text_img = Image.open(BytesIO(text_img_bytes)) if text_img_bytes else None
                if text_img and text_img.mode != 'RGBA':
                    text_img = text_img.convert('RGBA')
                    logger.debug(f"Converted text image to RGBA: {text_img.size}")
            except Exception as e:
                logger.error(f"Failed to generate text image: {e}")
                text_img = None
            
            text_img_height = text_img.height if text_img else 0
            logger.debug(f"Text image height: {text_img_height}")

            # ✅ 4" transparent margin between QR section and original image
            margin_4inch_px = int(2 * dpi_value)
            logger.debug(f"4-inch transparent margin: {margin_4inch_px}px")

            # ✅ Top section height = QR/text/logo area
            top_section_height = margin_height + text_img_height + 10 + logo_height + (logo_padding if logo_img else 0)

            # ✅ Total height = top section + 4" transparent margin + original image
            total_new_height = top_section_height + margin_4inch_px + original_height
            logger.info(f"Creating final image: {original_width} x {total_new_height}")

            # ✅ Always transparent canvas
            new_image = Image.new('RGBA', (original_width, total_new_height), (0, 0, 0, 0))

            # ✅ Paste original image at the bottom (after top section + 4" margin)
            if original_image.mode != 'RGBA':
                original_rgba = original_image.convert('RGBA')
            else:
                original_rgba = original_image

            new_image.paste(original_rgba, (0, top_section_height + margin_4inch_px), original_rgba)
            logger.debug("Pasted original image at bottom preserving transparency")

            # ✅ Place QR at TOP CENTER
            qr_x = (original_width - qr_size) // 2
            qr_y = (margin_height - padded_qr_height) // 2
            logger.debug(f"QR position: ({qr_x}, {qr_y})")

            new_image.paste(padded_qr_image, (qr_x, qr_y), padded_qr_image)
            logger.debug("QR code pasted to final image with transparency")

            # ✅ Place text under QR, within top section
            current_y = qr_y + padded_qr_height + 10
            if text_img:
                text_x = (original_width - text_img.width) // 2
                logger.debug(f"Text position: ({text_x}, {current_y})")
                new_image.paste(text_img, (text_x, current_y), text_img)
                logger.debug("Text image pasted to final image with transparency")
                current_y += text_img_height + logo_padding

            # ✅ Place logo under text, within top section
            if logo_img:
                logo_x = (original_width - logo_img.width) // 2
                new_image.paste(logo_img, (logo_x, current_y), logo_img)
                logger.debug("Logo pasted to final image")

            # Save final image
            img_io = BytesIO()
            new_image.save(img_io, format=image_format, dpi=(dpi_value, dpi_value))
            img_io.seek(0)
            
            final_size = len(img_io.getvalue())
            logger.info(f"QR code added successfully. Final image size: {final_size} bytes")
            return img_io
            
        except Exception as e:
            logger.error(f"Failed to add QR code to image: {e}")
            raise

# Create global processor instance
processor = ImageProcessor()
def upload_to_s3(file_content, s3_folder, file_name, content_type='image/png'):
    """Upload file content to S3"""
    logger.info(f"Uploading to S3: {s3_folder}/{file_name} (type: {content_type})")
    
    try:
        s3_key = f"{s3_folder}/{file_name}"
        content_length = len(file_content) if hasattr(file_content, '__len__') else 'unknown'
        logger.debug(f"S3 key: {s3_key}, content size: {content_length} bytes")
        
        s3_client.put_object(
            Bucket=S3_BUCKET,
            Key=s3_key,
            Body=file_content,
            ContentType=content_type
        )
        logger.info(f"✓ Uploaded {file_name} to S3 successfully")
        s3_url = f"s3://{S3_BUCKET}/{s3_key}"
        logger.debug(f"S3 URL: {s3_url}")
        return s3_url
        
    except NoCredentialsError:
        logger.error("AWS credentials not found")
        return None
    except ClientError as e:
        logger.error(f"S3 upload failed: {e}")
        return None
    except Exception as e:
        logger.error(f"Unexpected error during S3 upload: {e}")
        return None

def fetch_design_data(design_id):
    """Fetch design data from API"""
    logger.info(f"Fetching design data for ID: {design_id}")
    
    headers = {
        'Authorization': f'Bearer {API_TOKEN}',
        'Content-Type': 'application/json'
    }
    
    url = f"{API_URL}{design_id}"
    logger.debug(f"API URL: {url}")
    
    try:
        response = requests.get(url, headers=headers)
        logger.debug(f"API response status: {response.status_code}")
        
        if response.status_code != 200:
            logger.error(f"Failed to fetch design (Status: {response.status_code})")
            logger.error(f"Response details: {response.text}")
            return None
        
        data = response.json()
        logger.info("Design data fetched successfully")
        logger.debug(f"Design data keys: {list(data.keys()) if isinstance(data, dict) else 'Not a dict'}")
        return data
        
    except requests.exceptions.RequestException as e:
        logger.error(f"Network error fetching design data: {e}")
        return None
    except ValueError as e:
        logger.error(f"JSON decode error: {e}")
        return None
    except Exception as e:
        logger.error(f"Unexpected error fetching design data: {e}")
        return None

def download_image(image_url):
    """Download image from URL"""
    logger.info(f"Downloading image from: {image_url}")
    
    try:
        image_response = requests.get(image_url, timeout=30)
        logger.debug(f"Image download response status: {image_response.status_code}")
        
        if image_response.status_code != 200:
            logger.error(f"Failed to download image (Status: {image_response.status_code})")
            return None
        
        content_length = len(image_response.content)
        logger.info(f"Image downloaded successfully ({content_length} bytes)")
        return image_response.content
        
    except requests.exceptions.Timeout:
        logger.error("Image download timed out")
        return None
    except requests.exceptions.RequestException as e:
        logger.error(f"Network error downloading image: {e}")
        return None
    except Exception as e:
        logger.error(f"Unexpected error downloading image: {e}")
        return None

def process_single_image(design_id, order_id, item_id, product_id=None):
    """Process a single image"""
    logger.info(f"Processing single image: design_id={design_id}, order_id={order_id}, item_id={item_id}, product_id={product_id}")
    
    # Fetch design data
    design_data = fetch_design_data(design_id)
    if not design_data:
        logger.error("Failed to fetch design data")
        return None
    
    # Construct image URL
    file_name = design_data['design']['file_name']
    image_url = f"https://images.buildagangsheet.com/production/gang-sheets/369/{design_id}/{file_name}"
    logger.info(f"Image URL constructed: {image_url}")
    logger.debug(f"Original filename: {file_name}")
    
    # Download image
    image_content = download_image(image_url)
    if not image_content:
        logger.error("Failed to download image")
        return None
    
    # Process based on file type
    if not file_name.endswith('pdf'):
        logger.info("Processing as image file (adding QR code)")
        # Add QR code to image using the processor instance
        qr_content = f"{order_id}_{item_id}.png"
        logger.debug(f"QR content: {qr_content}")
        
        try:
            result_image = processor.add_qr_code_to_image_test(
                image_content, 
                qr_content=qr_content, 
                product_id=int(product_id) if product_id else -1,
                dpinfo=True
            )
            
            # Get the processed image content
            if hasattr(result_image, 'getvalue'):
                processed_content = result_image.getvalue()
                logger.debug(f"Processed image size: {len(processed_content)} bytes")
            else:
                processed_content = image_content
                logger.warning("Using original image content (no QR processing)")
            
            result = {
                'content': processed_content,
                'filename': f"{order_id}_{item_id}.png",
                'content_type': 'image/png'
            }
            logger.info(f"Single image processed successfully: {result['filename']}")
            return result
            
        except Exception as e:
            logger.error(f"Failed to process image with QR code: {e}")
            return None
    else:
        logger.info("Processing as PDF file (no QR code)")
        result = {
            'content': image_content,
            'filename': f"{order_id}_{item_id}.pdf",
            'content_type': 'application/pdf'
        }
        logger.info(f"PDF processed successfully: {result['filename']}")
        return result

def create_zip_with_multiple_files(design_id, order_id, item_id, quantity, product_id=None):
    """Create a zip file with multiple numbered files"""
    logger.info(f"Creating zip with multiple files: design_id={design_id}, quantity={quantity}")
    
    zip_buffer = BytesIO()
    
    # First, get the design data and download the base image once
    design_data = fetch_design_data(design_id)
    if not design_data:
        logger.error("Failed to fetch design data for zip creation")
        return None
    
    file_name = design_data['design']['file_name']
    image_url = f"https://images.buildagangsheet.com/production/gang-sheets/369/{design_id}/{file_name}"
    logger.info(f"Base image URL: {image_url}")
    
    base_image_content = download_image(image_url)
    if not base_image_content:
        logger.error("Failed to download base image for zip creation")
        return None
    
    try:
        with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
            logger.info(f"Creating zip file with {quantity} files...")
            
            for i in range(1, int(quantity) + 1):
                logger.info(f"Processing file {i} of {quantity}...")
                
                # Create numbered filename
                if not file_name.endswith('pdf'):
                    numbered_filename = f"{order_id}_{item_id}_{i}.png"
                    logger.debug(f"Creating image file: {numbered_filename}")
                    
                    # Add QR code with the numbered filename as content using processor instance
                    qr_content = numbered_filename
                    logger.debug(f"QR content for file {i}: {qr_content}")
                    
                    try:
                        result_image = processor.add_qr_code_to_image_test(
                            base_image_content, 
                            qr_content=qr_content, 
                            product_id=int(product_id) if product_id else -1,
                            dpinfo=True
                        )
                        
                        # Get the processed image content
                        if hasattr(result_image, 'getvalue'):
                            processed_content = result_image.getvalue()
                            logger.debug(f"File {i} processed size: {len(processed_content)} bytes")
                        else:
                            processed_content = base_image_content
                            logger.warning(f"File {i}: Using original content (no QR processing)")
                        
                        # Add to zip
                        zip_file.writestr(numbered_filename, processed_content)
                        logger.info(f"✓ Added {numbered_filename} to zip (QR content: {qr_content})")
                        
                    except Exception as e:
                        logger.error(f"Failed to process file {i}: {e}")
                        # Add original content as fallback
                        zip_file.writestr(numbered_filename, base_image_content)
                        logger.warning(f"Added {numbered_filename} without QR code as fallback")
                else:
                    numbered_filename = f"{order_id}_{item_id}_{i}.pdf"
                    logger.debug(f"Creating PDF file: {numbered_filename}")
                    # For PDFs, just add the original content with numbered name
                    zip_file.writestr(numbered_filename, base_image_content)
                    logger.info(f"✓ Added {numbered_filename} to zip")
        
        zip_buffer.seek(0)
        zip_size = len(zip_buffer.getvalue())
        logger.info(f"Zip file created successfully (size: {zip_size} bytes)")
        return zip_buffer.getvalue()
        
    except Exception as e:
        logger.error(f"Failed to create zip file: {e}")
        return None


def should_process(db_config, order_id, item_id, design_id=None, product_id=None, quantity=None):
    """
    Decide whether to process a file based on BPyN0vqr_processing_table state.
    Returns:
      (True, record_id)  → proceed with processing
      (False, record_id) → skip processing
    """
    try:
        conn = mysql.connector.connect(**db_config)
        cursor = conn.cursor(dictionary=True)

        cursor.execute("""
            SELECT id, status, retry_count
            FROM BPyN0vqr_processing_table
            WHERE order_id = %s AND item_id = %s
        """, (order_id, item_id))
        row = cursor.fetchone()

        if not row:
            # Insert new record
            cursor.execute("""
                INSERT INTO BPyN0vqr_processing_table
                (order_id, item_id, design_id, product_id, quantity, status, started_at, retry_count)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
            """, (order_id, item_id, design_id, product_id, quantity, "processing", datetime.now(), 0))

            conn.commit()
            record_id = cursor.lastrowid
            cursor.close()
            conn.close()
            return True, record_id

        # Case: already exists
        if row["status"] in ("completed", "error"):
            cursor.close()
            conn.close()
            return False, row["id"]

        if row["status"] == "processing":
            if row["retry_count"] >= 3:
                cursor.execute("""
                    UPDATE BPyN0vqr_processing_table
                    SET status = %s,
                        completed_at = %s,
                        error_message = %s
                    WHERE id = %s
                """, ("error", datetime.now(), "Exceeded max retries", row["id"]))
                conn.commit()
                cursor.close()
                conn.close()
                return False, row["id"]

            # Retry allowed → increment retry_count
            new_retry = row["retry_count"] + 1
            cursor.execute("""
                UPDATE BPyN0vqr_processing_table
                SET retry_count = %s,
                    started_at = %s
                WHERE id = %s
            """, (new_retry, datetime.now(), row["id"]))
            conn.commit()
            cursor.close()
            conn.close()
            return True, row["id"]

    except mysql.connector.Error as err:
        logger.error(f"Database error: {err}")
        return False, None


def check_s3_file_exists(url):
    """Check if an S3 file exists by sending a HEAD request."""
    try:
        response = requests.head(url)
        return response.status_code == 200
    except requests.RequestException:
        return False


def find_existing_file(base_path, formats=None):
    """Try multiple formats to see if a processed file exists in S3."""
    if formats is None:
        formats = ["png", "jpg", "jpeg", "pdf", "zip"]

    for fmt in formats:
        file_url = f"{base_path}.{fmt}"
        if check_s3_file_exists(file_url):
            return {"url": file_url, "format": fmt}
    return None


def update_status_post_process(db_config, order_id, item_id, s3_base_url, s3_folder="processed", product_id=0):
    """
    After attempting processing, check if the file exists on S3.
    Update status in the database accordingly.
    """
    conn = mysql.connector.connect(**db_config)
    cursor = conn.cursor(dictionary=True)

    base_path = f"{s3_base_url}/{s3_folder}/{order_id}/{item_id}/{order_id}_{item_id}"
    found_file = find_existing_file(base_path)

    cursor.execute("""
        SELECT id, status, retry_count
        FROM BPyN0vqr_processing_table
        WHERE order_id = %s AND item_id = %s
    """, (order_id, item_id))
    row = cursor.fetchone()

    if not row:
        cursor.close()
        conn.close()
        return  # safety net

    if found_file:
        # ✅ Mark as completed
        if int(product_id) in [32317, 32319, 32500, 28377]:
            cursor.execute("""
                UPDATE BPyN0vqr_processing_table
                SET status = %s,
                    completed_at = %s,
                    lambda_call = 1,
                    error_message = NULL
                WHERE id = %s
            """, ("completed", datetime.now(), row["id"]))
        else:
            cursor.execute("""
                UPDATE BPyN0vqr_processing_table
                SET status = %s,
                    completed_at = %s,
                    error_message = NULL
                WHERE id = %s
            """, ("completed", datetime.now(), row["id"]))

    else:
        # 🚫 No file found
        if row["retry_count"] >= 3:
            cursor.execute("""
                UPDATE BPyN0vqr_processing_table
                SET status = %s,
                    completed_at = %s,
                    error_message = %s
                WHERE id = %s
            """, ("error", datetime.now(), "No file found after retries", row["id"]))
        else:
            cursor.execute("""
                UPDATE BPyN0vqr_processing_table
                SET status = %s
                WHERE id = %s
            """, ("processing", row["id"]))

    conn.commit()
    cursor.close()
    conn.close()
def check_and_create_hot_peel_file(db_config, order_id):
    """
    Check if all items for specific products in an order are completed with lambda_call=0,
    then create and upload a peels.txt file listing the filenames.
    
    Args:
        db_config: Database configuration dictionary
        order_id: The order ID to check
    """
    
    HOT_PEEL_PRODUCTS = [32317, 32319, 32500, 28377]
    
    try:
        # Connect to database
        connection = mysql.connector.connect(**db_config)
        cursor = connection.cursor(dictionary=True)
        
        # Check if there are any items with hot peel products for this order
        check_query = """
            SELECT COUNT(*) as count 
            FROM BPyN0vqr_processing_table 
            WHERE order_id = %s AND product_id IN (%s, %s, %s, %s)
        """
        cursor.execute(check_query, (order_id, *HOT_PEEL_PRODUCTS))
        result = cursor.fetchone()
        
        if result['count'] == 0:
            print(f"[INFO] No hot peel products found for order {order_id}")
            cursor.close()
            connection.close()
            return
        
        # Check if all hot peel items are completed with status 'completed' and lambda_call = 0
        status_query = """
            SELECT item_id, status, lambda_call
            FROM BPyN0vqr_processing_table 
            WHERE order_id = %s AND product_id IN (%s, %s, %s, %s)
        """
        cursor.execute(status_query, (order_id, *HOT_PEEL_PRODUCTS))
        items = cursor.fetchall()
        
        # Check if all items are completed and lambda_call is 0
        all_completed = all(
            item['status'] == 'completed' and item['lambda_call'] == 1 
            for item in items
        )
        
        if not all_completed:
            print(f"[INFO] Not all hot peel items completed for order {order_id} or lambda_call != 0")
            cursor.close()
            connection.close()
            return
        
        print(f"[INFO] All hot peel items completed for order {order_id}. Creating peels.txt file...")
        
        # Create the file content with filenames (orderid_itemid format)
        file_content = ""
        for item in items:
            filename = f"{order_id}_{item['item_id']}"
            file_content += f"{filename}\n"
        
        # Upload to S3 using existing upload_to_s3 function
        s3_folder = f"processed/{order_id}/hot_peel"
        file_name = "peels.txt"
        
        s3_url = upload_to_s3(
            file_content=file_content.encode('utf-8'),
            s3_folder=s3_folder,
            file_name=file_name,
            content_type='text/plain'
        )
        
        if s3_url:
            print(f"[SUCCESS] Hot peel file uploaded to {s3_url}")
            print(f"[INFO] File contains {len(items)} filename(s)")
        else:
            print(f"[ERROR] Failed to upload hot peel file to S3")
        
    except mysql.connector.Error as db_error:
        print(f"[ERROR] Database error in check_and_create_hot_peel_file: {db_error}")
        if connection:
            connection.rollback()
    except Exception as e:
        print(f"[ERROR] Error in check_and_create_hot_peel_file: {type(e).__name__}: {str(e)}")
        import traceback
        traceback.print_exc()
    finally:
        if 'cursor' in locals() and cursor:
            cursor.close()
        if 'connection' in locals() and connection:
            connection.close()

def main():
    logger.info("=== STARTING IMAGE PROCESSING SCRIPT ===")
    
    try:
        logger.info("Creating argument parser...")
        parser = argparse.ArgumentParser(description='Process images and upload to S3')
        parser.add_argument('--design-id', required=True, help='Design ID (gs_design_id)')
        parser.add_argument('--order-id', required=True, help='Order ID')
        parser.add_argument("--dropshipping", type=int, help="dropshipping flag", default=0)
        parser.add_argument('--quantity', default=1, help='Quantity of files (default: 1)')
        parser.add_argument('--product-id', help='Product id')
        
        logger.info("Parsing command line arguments...")
        logger.debug(f"sys.argv: {sys.argv}")
        args = parser.parse_args()
        logger.info("Arguments parsed successfully")
        
        logger.info(f"Script arguments: design_id={args.design_id}, order_id={args.order_id}, quantity={args.quantity}, product_id={args.product_id}")
        
    except SystemExit as e:
        logger.error(f"SystemExit during argument parsing: {e}")
        logger.error("This usually means invalid arguments were provided")
        raise
    except Exception as e:
        logger.error(f"Unexpected error during argument parsing: {e}", exc_info=True)
        raise
    
    try:
        logger.info("Parsing order_id...")
        order_id, item_id = args.order_id.split('_')
        logger.info(f"Parsed order_id: {order_id}, item_id: {item_id}")
    except ValueError as e:
        logger.error(f"Failed to parse order_id '{args.order_id}': {e}")
        logger.error("order_id must be in format: 'orderid_itemid'")
        sys.exit(1)
    except Exception as e:
        logger.error(f"Unexpected error parsing order_id: {e}", exc_info=True)
        sys.exit(1)
    
    # Check if processing should proceed
    logger.info("Checking if processing should proceed...")
    try:
        should_run, record_id = should_process(
            db_config, 
            order_id=order_id, 
            item_id=item_id, 
            design_id=args.design_id, 
            product_id=args.product_id, 
            quantity=args.quantity
        )
        
        if not should_run:
            logger.info("⏭ Skipping processing - already completed or exceeded retries.")
            print("⏭ Skipping processing.")
            return
        
        logger.info("➡️ Proceeding with processing...")
        print("➡️ Proceed with processing...")
        
    except Exception as e:
        logger.error(f"Error in should_process: {e}", exc_info=True)
        print(f"Error checking processing status: {str(e)}")
        sys.exit(1)
    
    s3_folder = f"processed/{order_id}/{item_id}"
    logger.info(f"S3 folder: {s3_folder}")
    
    # Test AWS credentials early
    logger.info("Testing AWS credentials...")
    try:
        s3_client.list_buckets()
        logger.info("AWS credentials verified successfully")
    except Exception as e:
        logger.warning(f"AWS credentials test failed: {e}")
        logger.warning("Continuing anyway, upload may fail later")
    
    logger.info("Starting main processing logic...")
    
    try:
        if int(args.quantity) == 1:
            # Single file processing
            logger.info("=== SINGLE FILE PROCESSING MODE ===")
            file_data = process_single_image(args.design_id, order_id, item_id, args.product_id)
            
            if not file_data:
                logger.error("Failed to process single image")
                sys.exit(1)
            
            # Upload to S3
            logger.info("Uploading single file to S3...")
            s3_url = upload_to_s3(file_data['content'], s3_folder, file_data['filename'], file_data['content_type'])
            
            if s3_url:
                logger.info(f"✓ Single file uploaded successfully: {s3_url}")
                print(f"✓ File uploaded successfully: {s3_url}")
            else:
                logger.error("Failed to upload single file to S3")
                print("Failed to upload to S3")
                sys.exit(1)
                
        else:
            # Multiple files - create zip
            logger.info("=== MULTIPLE FILES (ZIP) PROCESSING MODE ===")
            zip_content = create_zip_with_multiple_files(
                args.design_id, order_id, item_id, args.quantity, args.product_id
            )
            
            if not zip_content:
                logger.error("Failed to create zip file")
                print("Failed to create zip file")
                sys.exit(1)
            
            # Upload zip to S3
            zip_filename = f"{order_id}_{item_id}.zip"
            logger.info(f"Uploading zip file to S3: {zip_filename}")
            s3_url = upload_to_s3(zip_content, s3_folder, zip_filename, 'application/zip')
            
            if s3_url:
                logger.info(f"✓ Zip file uploaded successfully: {s3_url}")
                print(f"✓ Zip file uploaded successfully: {s3_url}")
            else:
                logger.error("Failed to upload zip file to S3")
                print("Failed to upload zip to S3")
                sys.exit(1)
        
        logger.info("=== SCRIPT COMPLETED SUCCESSFULLY ===")
                
    except Exception as e:
        logger.error(f"Script failed with error: {e}", exc_info=True)
        print(f"Error: {str(e)}")
        sys.exit(1)
    
    finally:
        # Update status after processing attempt
        logger.info("Updating processing status...")
        try:
            # Construct S3 base URL - you may need to adjust this based on your S3 bucket configuration
            s3_base_url=f"https://{S3_BUCKET}.s3.us-east-1.amazonaws.com"  # Update these variables as needed
            update_status_post_process(
                db_config,
                order_id=order_id,
                item_id=item_id,
                s3_base_url=s3_base_url,
                product_id=args.product_id,
            )
            check_and_create_hot_peel_file(db_config=db_config, order_id=order_id)
            logger.info("Status updated successfully")
        except Exception as e:
            logger.error(f"Failed to update status: {e}", exc_info=True)


if __name__ == "__main__":
    logger.info(f"Starting process with PID: {os.getpid()}")
    logger.info(f"Python version: {sys.version}")
    logger.info(f"Script path: {sys.argv[0]}")
    logger.info(f"Working directory: {os.getcwd()}")
    logger.info(f"Command line args: {sys.argv}")
    
  
    logger.info("Waiting 60 seconds before starting main processing...")
    sleep(60)
    
    try:
        main()
    except KeyboardInterrupt:
        logger.error("Script interrupted by user")
        sys.exit(130)
    except SystemExit as e:
        logger.error(f"Script exited with code: {e.code}")
        raise
    except Exception as e:
        logger.error(f"Unhandled exception in main: {e}", exc_info=True)
        sys.exit(1)