import qrcode
from PIL import Image
import gradio as gr
import io
import base64
import numpy as np
import cv2
import tempfile


# Function to generate a QR code and return Base64 and PNG file
def generate_qr(data):
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image(fill="black", back_color="white")

    # Encode the image as a base64 string
    buffered = io.BytesIO()
    img.save(buffered, format="PNG")
    img_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")

    # Save the image temporarily as a PNG file
    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
    img.save(temp_file.name, format="PNG")
    temp_file.close()

    return f"data:image/png;base64,{img_base64}", temp_file.name, img_base64


# Function to decode a QR code from an uploaded image
def decode_qr(img):
    if img is None:
        return "No image uploaded."
    
    # Convert PIL image to a NumPy array
    img_array = np.array(img)

    # Convert RGB to BGR as OpenCV expects
    if img_array.ndim == 3:
        img_array = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)

    # Initialize OpenCV QR code detector
    detector = cv2.QRCodeDetector()
    data, _, _ = detector.detectAndDecode(img_array)
    return data if data else "No QR code found."


# Gradio Interface
def create_gradio_interface():
    with gr.Blocks() as demo:
        gr.Markdown("## QR Code Generator and Decoder")

        # Tab for generating QR codes
        with gr.Tab("Generate QR Code"):
            with gr.Row():
                data_input = gr.Textbox(placeholder="Enter text or URL to encode", label="Input Data")
                generate_button = gr.Button("Generate QR Code")

            qr_code_html = gr.HTML(label="Generated QR Code (Base64 Embedded)")
            qr_png_file = gr.File(label="Download QR Code (PNG)")
            qr_base64_file = gr.File(label="Download Base64 (TXT)")

            def generate_qr_interface(data):
                if not data.strip():
                    raise ValueError("Input text cannot be empty!")
                img_base64, png_path, base64_str = generate_qr(data)
                
                # Save Base64 string as a .txt file
                base64_txt_path = tempfile.NamedTemporaryFile(delete=False, suffix=".txt")
                with open(base64_txt_path.name, "w") as f:
                    f.write(base64_str)

                # Wrap the base64 string in an <img> tag for display
                html_content = f'<img src="{img_base64}" alt="QR Code" style="max-width:300px;">'
                return html_content, png_path, base64_txt_path.name

            generate_button.click(
                generate_qr_interface,
                inputs=data_input,
                outputs=[qr_code_html, qr_png_file, qr_base64_file],
            )

        # Tab for decoding QR codes
        with gr.Tab("Decode QR Code"):
            with gr.Row():
                image_input = gr.Image(type="pil", label="Upload QR Code Image")
                decode_button = gr.Button("Decode QR Code")

            decoded_text = gr.Textbox(label="Decoded Text", interactive=True)

            decode_button.click(
                decode_qr,
                inputs=image_input,
                outputs=decoded_text,
            )

        # Add the logo at the bottom center using gr.HTML
        gr.HTML("""
            <div style="
                position: fixed;
                bottom: 20px;
                left: 50%;
                transform: translateX(-50%);
                z-index: 1000;
            ">
                <img src="file=space-logo.png" alt="Space Logo" style="width: 150px; height: auto;">
            </div>
        """)

    demo.launch(share=True)


# Run the Gradio interface
create_gradio_interface()