from fastapi import FastAPI, File, UploadFile, Form, HTTPException
from fastapi.responses import JSONResponse, FileResponse
from fastapi.middleware.cors import CORSMiddleware
from qrcode import QRCode, constants
from PIL import Image
import io
import uuid
import os
from typing import Optional, List
import base64
import json
from datetime import datetime
import threading
import time

app = FastAPI()

# Configure CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000", "https://backqr.okhubtech.com/", "https://qr.okhubtech.com/"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Directory to store generated QR codes
QR_CODE_DIR = "qr_codes"
if not os.path.exists(QR_CODE_DIR):
    os.makedirs(QR_CODE_DIR)

def generate_qr_code(data: str, size: int, border: int, logo: Optional[bytes] = None):
    qr = QRCode(
        version=1,
        error_correction=constants.ERROR_CORRECT_H,
        box_size=size,
        border=border,
    )
    qr.add_data(data)
    qr.make(fit=True)
    qr_img = qr.make_image(fill_color="black", back_color="white").convert('RGBA')

    if logo:
        logo_img = Image.open(io.BytesIO(logo)).convert('RGBA')
        qr_width, qr_height = qr_img.size
        logo_size = min(qr_width, qr_height) // 4
        logo_img = logo_img.resize((logo_size, logo_size), Image.Resampling.LANCZOS)
        logo_position = ((qr_width - logo_size) // 2, (qr_height - logo_size) // 2)
        qr_img.paste(logo_img, logo_position, logo_img)

    # Check file size
    buffered = io.BytesIO()
    qr_img.save(buffered, format="PNG", optimize=True, quality=85)
    if buffered.tell() > 2 * 1024 * 1024:  # 2MB limit
        raise HTTPException(status_code=400, detail="Generated QR code exceeds 2MB limit")
    
    return qr_img, buffered.getvalue()

def format_qr_data(qr_type: str, data: dict):
    if qr_type == "url":
        return data.get("url", "")
    elif qr_type == "text":
        return data.get("text", "")
    elif qr_type == "email":
        return f"mailto:{data.get('email','')}?subject={data.get('subject','')}&body={data.get('body','')}"
    elif qr_type == "sms":
        return f"sms:{data.get('phone','')}?body={data.get('message','')}"
    elif qr_type == "phone":
        return f"tel:{data.get('phone','')}"
    elif qr_type == "whatsapp":
        return f"https://wa.me/{data.get('phone','')}?text={data.get('message','')}"
    elif qr_type == "facetime":
        return f"facetime:{data.get('id','')}"
    elif qr_type == "location":
        return f"geo:{data.get('latitude','0')},{data.get('longitude','0')}"
    elif qr_type == "wifi":
        return f"WIFI:S:{data.get('ssid','')};T:{data.get('encryption','')};P:{data.get('password','')};H:{data.get('hidden','false')};;"
    elif qr_type == "event":
        start = datetime.strptime(data.get('start',''), "%Y-%m-%dT%H:%M") if data.get('start') else datetime.now()
        end = datetime.strptime(data.get('end',''), "%Y-%m-%dT%H:%M") if data.get('end') else start
        return (
            f"BEGIN:VEVENT\n"
            f"SUMMARY:{data.get('title','')}\n"
            f"DTSTART:{start.strftime('%Y%m%dT%H%M%S')}\n"
            f"DTEND:{end.strftime('%Y%m%dT%H%M%S')}\n"
            f"LOCATION:{data.get('location','')}\n"
            f"DESCRIPTION:{data.get('description','')}\n"
            f"END:VEVENT"
        )
    elif qr_type == "crypto":
        return f"{data.get('currency','bitcoin')}:{data.get('address','')}?amount={data.get('amount','')}"
    elif qr_type == "vcard":
        return (
            f"BEGIN:VCARD\nVERSION:3.0\n"
            f"N:{data.get('lastName','')};{data.get('firstName','')};;;\n"
            f"FN:{data.get('firstName','')} {data.get('lastName','')}\n"
            f"ORG:{data.get('organization','')}\n"
            f"TEL;TYPE=WORK:{data.get('phone','')}\n"
            f"EMAIL:{data.get('email','')}\n"
            f"URL:{data.get('website','')}\n"
            f"ADR:{data.get('address','')}\n"
            f"END:VCARD"
        )
    elif qr_type == "paypal":
        return f"https://www.paypal.com/paypalme/{data.get('username','')}?amount={data.get('amount','')}"
    elif qr_type == "paystack":
        return f"https://paystack.com/pay/{data.get('paystack_id','')}?amount={data.get('amount','') * 100}"  # Paystack uses kobo
    elif qr_type == "flutterwave":
        return f"https://flutterwave.com/pay/{data.get('flw_id','')}?amount={data.get('amount','')}"
    elif qr_type == "mp3":
        return data.get("url", "")
    elif qr_type == "pdf":
        return data.get("url", "")
    elif qr_type == "image":
        return data.get("url", "")
    elif qr_type == "appstores":
        return data.get("url", "")
    elif qr_type == "social":
        return data.get("url", "")
    elif qr_type == "menu":
        return data.get("url", "")
    elif qr_type == "feedback":
        return data.get("url", "")
    elif qr_type == "zoom":
        return f"https://zoom.us/j/{data.get('meeting_id','')}?pwd={data.get('password','')}"
    elif qr_type == "coupon":
        return data.get("url", "")
    return ""

@app.post("/generate-qr/")
async def generate_qr(
    qr_types: str = Form(...),
    data_list: str = Form(...),
    logo: Optional[UploadFile] = File(None),
    size: int = Form(10),
    border: int = Form(4)
):
    try:
        qr_id = str(uuid.uuid4())
        qr_path = os.path.join(QR_CODE_DIR, f"{qr_id}.png")
        qr_types_list = json.loads(qr_types)
        data_list_obj = json.loads(data_list)

        if len(qr_types_list) != len(data_list_obj):
            raise HTTPException(status_code=400, detail="Mismatch between QR types and data")

        # Validate logo size
        logo_data = None
        if logo:
            logo_data = await logo.read()
            if len(logo_data) > 2 * 1024 * 1024:
                raise HTTPException(status_code=400, detail="Logo file exceeds 2MB limit")

        # If multiple QR types, save data and encode landing page URL
        if len(qr_types_list) > 1:
            # Save the QR entry data to a JSON file
            landing_data = {
                "qr_types": qr_types_list,
                "data_list": data_list_obj
            }
            landing_path = os.path.join(QR_CODE_DIR, f"{qr_id}.json")
            with open(landing_path, "w") as f:
                json.dump(landing_data, f)
            # Encode the landing page URL in the QR code
            landing_url = f"https://qr.okhubtech.com/qr/{qr_id}/landing"
            formatted_data = landing_url
        else:
            # Single QR type: encode as before
            formatted_data = format_qr_data(qr_types_list[0], data_list_obj[0])

        qr_img, qr_bytes = generate_qr_code(formatted_data, size, border, logo_data)
        qr_img.save(qr_path)

        img_str = base64.b64encode(qr_bytes).decode()

        return JSONResponse({
            "qr_id": qr_id,
            "qr_image": f"data:image/png;base64,{img_str}",
            "url": f"/qr/{qr_id}"
        })

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/qr/{qr_id}")
async def get_qr(qr_id: str):
    qr_path = os.path.join(QR_CODE_DIR, f"{qr_id}.png")
    if not os.path.exists(qr_path):
        raise HTTPException(status_code=404, detail="QR code not found")
    return FileResponse(qr_path)

@app.get("/qr/{qr_id}/landing")
async def get_qr_landing(qr_id: str):
    landing_path = os.path.join(QR_CODE_DIR, f"{qr_id}.json")
    if not os.path.exists(landing_path):
        raise HTTPException(status_code=404, detail="Landing data not found")
    with open(landing_path, "r") as f:
        landing_data = json.load(f)
    return landing_data

@app.post("/qr/{qr_id}/delete")
async def schedule_delete_qr(qr_id: str):
    qr_path = os.path.join(QR_CODE_DIR, f"{qr_id}.png")
    if not os.path.exists(qr_path):
        raise HTTPException(status_code=404, detail="QR code not found")
    def delete_file_later(path):
        time.sleep(300)  # 5 minutes
        if os.path.exists(path):
            os.remove(path)
    threading.Thread(target=delete_file_later, args=(qr_path,), daemon=True).start()
    return {"status": "scheduled for deletion in 5 minutes"}