from flask import Blueprint, request, jsonify, send_from_directory
from flask_jwt_extended import jwt_required, get_jwt_identity
from db.db import get_db_connection
from config.auth import role_required
import mysql.connector
import traceback
from datetime import datetime
from werkzeug.security import generate_password_hash
from werkzeug.utils import secure_filename
import base64
import os
from PIL import Image
import io

cashier_bp = Blueprint('cashier', __name__)

# ==========================================
# FILE UPLOAD CONFIGURATION
# ==========================================
UPLOAD_FOLDER = 'static/uploads/profile'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

MAX_IMAGE_SIZE = 5 * 1024 * 1024  # 5MB
IMAGE_QUALITY = 55
IMAGE_MAX_DIMENSION = 200

# ==========================================
# SERVE UPLOADED FILES
# ==========================================
@cashier_bp.route('/uploads/profile/<filename>', methods=['GET'])
def serve_profile_image(filename):
    """Serve uploaded profile images"""
    try:
        return send_from_directory(UPLOAD_FOLDER, filename)
    except FileNotFoundError:
        return jsonify({'error': 'File not found'}), 404


# ==========================================
# CONVERT FILE PATH TO BASE64
# ==========================================
def filepath_to_base64(filepath):
    """
    Convert image file to base64 string for frontend display
    Returns: base64 string or None
    """
    try:
        if not filepath or not os.path.exists(filepath):
            return None
        
        with open(filepath, 'rb') as image_file:
            image_data = image_file.read()
            base64_string = base64.b64encode(image_data).decode('utf-8')
            return base64_string
    except Exception as e:
        print(f"❌ Error converting image to base64: {e}")
        return None


# ==========================================
# SAVE IMAGE TO DISK
# ==========================================
def save_image_to_disk(base64_data, prefix='cashier'):
    """
    Save and optimize base64 image to disk
    Returns: filepath (e.g., 'static/uploads/profile/cashier_20240215_123456.jpg')
    """
    try:
        # Remove header if present
        if ',' in base64_data:
            header, encoded = base64_data.split(',', 1)
        else:
            encoded = base64_data
            header = 'data:image/jpeg;base64'
        
        # Decode base64 to bytes
        image_bytes = base64.b64decode(encoded)
        
        # Open image with PIL
        img = Image.open(io.BytesIO(image_bytes))
        
        # Convert RGBA to RGB if necessary
        if img.mode in ('RGBA', 'LA', 'P'):
            background = Image.new('RGB', img.size, (255, 255, 255))
            if img.mode == 'P':
                img = img.convert('RGBA')
            background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
            img = background
        
        # Resize if needed
        if img.width > IMAGE_MAX_DIMENSION or img.height > IMAGE_MAX_DIMENSION:
            img.thumbnail((IMAGE_MAX_DIMENSION, IMAGE_MAX_DIMENSION), Image.Resampling.LANCZOS)
            print(f"🔄 Resized image to {img.width}x{img.height}")
        
        # Generate unique filename
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S_%f')
        filename = secure_filename(f"{prefix}_{timestamp}.jpg")
        filepath = os.path.join(UPLOAD_FOLDER, filename)
        
        # Save optimized image
        img.save(filepath, format='JPEG', quality=IMAGE_QUALITY, optimize=True)
        
        # Get file size
        file_size = os.path.getsize(filepath)
        
        print(f"💾 Saved image: {filepath} ({file_size:,} bytes = {file_size/1024:.1f}KB)")
        
        return filepath
        
    except Exception as e:
        print(f"❌ Error saving image: {e}")
        traceback.print_exc()
        return None


# ==========================================
# DELETE OLD IMAGE
# ==========================================
def delete_old_image(image_path):
    """Delete old image file from disk"""
    try:
        if image_path and os.path.exists(image_path):
            os.remove(image_path)
            print(f"🗑️ Deleted old image: {image_path}")
            return True
    except Exception as e:
        print(f"⚠️ Could not delete old image: {e}")
    return False


# ==========================================
# CREATE CASHIER
# ==========================================
@cashier_bp.route('/create_cashier', methods=['POST'])
@jwt_required()
@role_required('admin', 'manager')
def create_cashier():
    """
    Create a new cashier user
    Required: name, email, password
    Optional: contact, address, image, store_id
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({'error': 'No data provided'}), 400
    except Exception as e:
        return jsonify({'error': 'Invalid JSON data', 'message': str(e)}), 400

    # Extract fields
    name = data.get('name', '').strip()
    email = data.get('email', '').strip()
    password = data.get('password', '').strip()
    contact = data.get('contact', '').strip()
    address = data.get('address', '').strip()
    image = data.get('image')  # Base64 encoded image
    store_id = data.get('store_id')

    # Validation
    if not name:
        return jsonify({'error': 'Cashier name is required'}), 400
    
    if not email:
        return jsonify({'error': 'Email is required'}), 400
    
    if not password:
        return jsonify({'error': 'Password is required'}), 400

    # Email validation
    import re
    email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(email_pattern, email):
        return jsonify({'error': 'Invalid email format'}), 400

    # Password validation
    if len(password) < 6:
        return jsonify({'error': 'Password must be at least 6 characters'}), 400

    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection failed'}), 500

    cursor = conn.cursor(dictionary=True)

    try:
        # Check for duplicate email
        cursor.execute("SELECT id FROM users WHERE email = %s", (email,))
        existing = cursor.fetchone()
        if existing:
            return jsonify({
                'error': 'Email already exists',
                'duplicate': True
            }), 409

        # Hash password
        hashed_password = generate_password_hash(password)

        # Handle image - save to disk and get filepath
        image_path = None
        if image:
            print("🖼️ Processing cashier image...")
            image_path = save_image_to_disk(image, prefix='cashier')
            
            if image_path:
                print(f"✅ Image saved successfully: {image_path}")
            else:
                print("⚠️ Image save failed")

        # Insert cashier
        sql = """
            INSERT INTO users (name, email, contact, address, password, role, image, store_id, is_active)
            VALUES (%s, %s, %s, %s, %s, 'cashier', %s, %s, 1)
        """
        values = (
            name,
            email,
            contact if contact else None,
            address if address else None,
            hashed_password,
            image_path,  # Store file path instead of base64
            store_id if store_id else None
        )

        cursor.execute(sql, values)
        conn.commit()

        cashier_id = cursor.lastrowid

        print(f"✅ Cashier created successfully: ID {cashier_id}, Name: {name}")

        return jsonify({
            'success': True,
            'message': 'Cashier created successfully',
            'cashier_id': cashier_id,
            'cashier_name': name
        }), 201

    except mysql.connector.Error as err:
        print(f"❌ MySQL Error: {err}")
        traceback.print_exc()
        
        # Delete uploaded image if database insert failed
        if image_path:
            delete_old_image(image_path)
        
        return jsonify({'error': f'Database error: {str(err)}'}), 500

    finally:
        cursor.close()
        conn.close()


# ==========================================
# GET ALL CASHIERS
# ==========================================
@cashier_bp.route('/get_cashiers', methods=['GET'])
@jwt_required()
@role_required('admin', 'manager')
def get_cashiers():
    """
    Get all cashiers with pagination and store filtering
    ✅ Returns base64 images for frontend display
    """
    try:
        page = int(request.args.get('page', 1))
        per_page = int(request.args.get('per_page', 20))
        search = request.args.get('search', '').strip()
        store_id = request.args.get('store_id')
        
        offset = (page - 1) * per_page

        conn = get_db_connection()
        if not conn:
            return jsonify({'error': 'Database connection failed'}), 500

        cursor = conn.cursor(dictionary=True)

        # Build WHERE clause
        where_clause = "WHERE role = 'cashier'"
        params = []

        if store_id:
            where_clause += " AND u.store_id = %s"
            params.append(int(store_id))

        if search:
            where_clause += """
                AND (u.name LIKE %s 
                OR u.contact LIKE %s 
                OR u.email LIKE %s)
            """
            search_pattern = f"%{search}%"
            params.extend([search_pattern, search_pattern, search_pattern])

        # Get total count
        count_sql = f"SELECT COUNT(*) as total FROM users u {where_clause}"
        cursor.execute(count_sql, params)
        total = cursor.fetchone()['total']

        # Get cashiers
        sql = f"""
            SELECT 
                u.id,
                u.name,
                u.email,
                u.contact,
                u.address,
                u.image,
                u.store_id,
                u.is_active,
                s.store_name
            FROM users u
            LEFT JOIN stores s ON u.store_id = s.id
            {where_clause}
            ORDER BY u.name ASC
            LIMIT %s OFFSET %s
        """
        cursor.execute(sql, params + [per_page, offset])
        cashiers = cursor.fetchall()

        # ✅ Convert file paths to base64 for frontend display
        for cashier in cashiers:
            if cashier['image']:
                # Convert filepath to base64
                base64_image = filepath_to_base64(cashier['image'])
                cashier['image'] = base64_image

        return jsonify({
            'success': True,
            'cashiers': cashiers,
            'pagination': {
                'page': page,
                'per_page': per_page,
                'total': total,
                'pages': (total + per_page - 1) // per_page
            }
        }), 200

    except Exception as e:
        print(f"❌ Error fetching cashiers: {e}")
        traceback.print_exc()
        return jsonify({'error': str(e)}), 500

    finally:
        cursor.close()
        conn.close()


# ==========================================
# GET SINGLE CASHIER
# ==========================================
@cashier_bp.route('/get_cashier/<int:cashier_id>', methods=['GET'])
@jwt_required()
@role_required('admin', 'manager')
def get_cashier(cashier_id):
    """
    Get single cashier by ID
    ✅ Returns base64 image for frontend display
    """
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection failed'}), 500

    cursor = conn.cursor(dictionary=True)

    try:
        sql = """
            SELECT 
                u.id,
                u.name,
                u.email,
                u.contact,
                u.address,
                u.image,
                u.store_id,
                u.is_active,
                s.store_name
            FROM users u
            LEFT JOIN stores s ON u.store_id = s.id
            WHERE u.id = %s AND u.role = 'cashier'
        """
        cursor.execute(sql, (cashier_id,))
        cashier = cursor.fetchone()

        if not cashier:
            return jsonify({'error': 'Cashier not found'}), 404

        # ✅ Convert filepath to base64 for frontend display
        if cashier['image']:
            base64_image = filepath_to_base64(cashier['image'])
            cashier['image'] = base64_image

        return jsonify({
            'success': True,
            'cashier': cashier
        }), 200

    except Exception as e:
        print(f"❌ Error fetching cashier: {e}")
        traceback.print_exc()
        return jsonify({'error': str(e)}), 500

    finally:
        cursor.close()
        conn.close()


# ==========================================
# UPDATE CASHIER
# ==========================================
@cashier_bp.route('/update_cashier/<int:cashier_id>', methods=['PUT'])
@jwt_required()
@role_required('admin', 'manager')
def update_cashier(cashier_id):
    """
    Update cashier details
    Required: name, email
    Optional: contact, address, image, store_id, password
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({'error': 'No data provided'}), 400
    except Exception as e:
        return jsonify({'error': 'Invalid JSON data', 'message': str(e)}), 400

    # Extract fields
    name = data.get('name', '').strip()
    email = data.get('email', '').strip()
    contact = data.get('contact', '').strip()
    address = data.get('address', '').strip()
    image = data.get('image')
    store_id = data.get('store_id')
    password = data.get('password', '').strip()

    # Validation
    if not name:
        return jsonify({'error': 'Cashier name is required'}), 400
    
    if not email:
        return jsonify({'error': 'Email is required'}), 400

    # Email validation
    import re
    email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    if not re.match(email_pattern, email):
        return jsonify({'error': 'Invalid email format'}), 400

    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection failed'}), 500

    cursor = conn.cursor(dictionary=True)

    try:
        # Check if cashier exists and get old image path
        cursor.execute(
            "SELECT image FROM users WHERE id = %s AND role = 'cashier'",
            (cashier_id,)
        )
        existing = cursor.fetchone()
        
        if not existing:
            return jsonify({'error': 'Cashier not found'}), 404
        
        old_image_path = existing['image']

        # Check for duplicate email (excluding current user)
        cursor.execute("SELECT id FROM users WHERE email = %s AND id != %s", (email, cashier_id))
        if cursor.fetchone():
            return jsonify({'error': 'Email already exists'}), 409

        # Build update query
        update_fields = []
        values = []

        update_fields.append("name = %s")
        values.append(name)

        update_fields.append("email = %s")
        values.append(email)

        update_fields.append("contact = %s")
        values.append(contact if contact else None)

        update_fields.append("address = %s")
        values.append(address if address else None)

        # Handle image update
        if image:
            print("🖼️ Processing updated cashier image...")
            new_image_path = save_image_to_disk(image, prefix='cashier')
            
            if new_image_path:
                update_fields.append("image = %s")
                values.append(new_image_path)
                print(f"✅ New image saved: {new_image_path}")
                
                # Delete old image after successful save
                if old_image_path:
                    delete_old_image(old_image_path)
            else:
                print("⚠️ New image save failed, keeping old image")

        update_fields.append("store_id = %s")
        values.append(store_id if store_id else None)

        # Update password if provided
        if password:
            if len(password) < 6:
                return jsonify({'error': 'Password must be at least 6 characters'}), 400
            hashed_password = generate_password_hash(password)
            update_fields.append("password = %s")
            values.append(hashed_password)

        values.append(cashier_id)

        sql = f"""
            UPDATE users
            SET {', '.join(update_fields)}
            WHERE id = %s
        """

        cursor.execute(sql, values)
        conn.commit()

        print(f"✅ Cashier updated successfully: ID {cashier_id}, Name: {name}")

        return jsonify({
            'success': True,
            'message': 'Cashier updated successfully',
            'cashier_id': cashier_id,
            'cashier_name': name
        }), 200

    except mysql.connector.Error as err:
        print(f"❌ MySQL Error: {err}")
        traceback.print_exc()
        return jsonify({'error': f'Database error: {str(err)}'}), 500

    finally:
        cursor.close()
        conn.close()


# ==========================================
# DELETE CASHIER
# ==========================================
@cashier_bp.route('/delete_cashier/<int:cashier_id>', methods=['DELETE'])
@jwt_required()
@role_required('admin')
def delete_cashier(cashier_id):
    """
    Delete cashier (admin only)
    """
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection failed'}), 500

    cursor = conn.cursor(dictionary=True)

    try:
        # Check if cashier exists and get image path
        cursor.execute(
            "SELECT name, image FROM users WHERE id = %s AND role = 'cashier'",
            (cashier_id,)
        )
        cashier = cursor.fetchone()
        
        if not cashier:
            return jsonify({'error': 'Cashier not found'}), 404

        cashier_name = cashier['name']
        image_path = cashier['image']

        # Delete cashier
        cursor.execute("DELETE FROM users WHERE id = %s", (cashier_id,))
        conn.commit()

        # Delete image file
        if image_path:
            delete_old_image(image_path)

        print(f"✅ Cashier deleted successfully: ID {cashier_id}, Name: {cashier_name}")

        return jsonify({
            'success': True,
            'message': 'Cashier deleted successfully',
            'cashier_id': cashier_id,
            'cashier_name': cashier_name
        }), 200

    except mysql.connector.IntegrityError as err:
        print(f"❌ Integrity Error: {err}")
        return jsonify({
            'error': 'Cannot delete cashier. Cashier has related records (sales, etc.)'
        }), 400

    except mysql.connector.Error as err:
        print(f"❌ MySQL Error: {err}")
        traceback.print_exc()
        return jsonify({'error': f'Database error: {str(err)}'}), 500

    finally:
        cursor.close()
        conn.close()


# ==========================================
# TOGGLE CASHIER STATUS
# ==========================================
@cashier_bp.route('/toggle_cashier_status/<int:cashier_id>', methods=['PUT'])
@jwt_required()
@role_required('admin', 'manager')
def toggle_cashier_status(cashier_id):
    """
    Toggle cashier active/inactive status
    """
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection failed'}), 500

    cursor = conn.cursor(dictionary=True)

    try:
        # Get current status
        cursor.execute(
            "SELECT name, is_active FROM users WHERE id = %s AND role = 'cashier'",
            (cashier_id,)
        )
        cashier = cursor.fetchone()
        
        if not cashier:
            return jsonify({'error': 'Cashier not found'}), 404

        # Toggle status
        new_status = 0 if cashier['is_active'] == 1 else 1
        
        cursor.execute(
            "UPDATE users SET is_active = %s WHERE id = %s",
            (new_status, cashier_id)
        )
        conn.commit()

        status_text = "activated" if new_status == 1 else "deactivated"
        
        return jsonify({
            'success': True,
            'message': f'Cashier {status_text} successfully',
            'cashier_id': cashier_id,
            'is_active': new_status
        }), 200

    except mysql.connector.Error as err:
        print(f"❌ MySQL Error: {err}")
        traceback.print_exc()
        return jsonify({'error': f'Database error: {str(err)}'}), 500

    finally:
        cursor.close()
        conn.close()


# ==========================================
# CASHIER STATISTICS
# ==========================================
@cashier_bp.route('/cashiers/count', methods=['GET'])
@jwt_required()
@role_required('admin', 'manager')
def get_cashier_count():
    """Get total cashier count"""
    try:
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) FROM users WHERE role = 'cashier'")
        (count,) = cursor.fetchone()
        return jsonify({'total_cashiers': count}), 200
    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'Failed to get count: {str(e)}'}), 500
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()


@cashier_bp.route('/cashiers/active-count', methods=['GET'])
@jwt_required()
@role_required('admin', 'manager')
def get_active_cashier_count():
    """Get active cashier count"""
    try:
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute("SELECT COUNT(*) FROM users WHERE role = 'cashier' AND is_active = 1")
        (count,) = cursor.fetchone()
        return jsonify({'active_cashiers': count}), 200
    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'Failed to get count: {str(e)}'}), 500
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()