"""
QRGenerator - Generate beautiful QR codes with custom styling.
"""

import asyncio
import os
import tempfile
from typing import Optional, Tuple
import logging

logger = logging.getLogger("zehnex.qrcode")


class QRGenerator:
    """
    Generate QR codes for URLs, text, contact info, WiFi passwords and more.

    Example:
        qr = QRGenerator()

        @bot.command("qr")
        async def qr_cmd(ctx):
            if not ctx.args:
                await ctx.reply("QR yasash uchun matn yuboring!\nMisol: /qr https://example.com")
                return

            data = " ".join(ctx.args)
            await ctx.typing()

            path = await qr.generate(data, style="rounded", color="#1a237e")
            await ctx.send_photo(path, caption=f"✅ QR kod tayyor!\n📝 {data[:50]}")
            qr.cleanup(path)

        # WiFi QR:
        @bot.command("wifi")
        async def wifi_cmd(ctx):
            # /wifi MyNetwork MyPassword WPA
            args = ctx.args
            path = await qr.wifi(ssid=args[0], password=args[1], security=args[2])
            await ctx.send_photo(path, caption="📶 WiFi QR kod")
            qr.cleanup(path)
    """

    STYLES = ("square", "rounded", "circle", "gapped_square")

    def __init__(self, output_dir: Optional[str] = None, default_size: int = 400):
        self.output_dir = output_dir or tempfile.gettempdir()
        self.default_size = default_size
        os.makedirs(self.output_dir, exist_ok=True)

    async def generate(
        self,
        data: str,
        filename: Optional[str] = None,
        color: str = "#000000",
        background: str = "#FFFFFF",
        style: str = "square",
        size: int = 400,
        logo_path: Optional[str] = None,
        border: int = 4,
        error_correction: str = "H",
    ) -> str:
        """
        Generate a QR code image.

        Args:
            data: Content to encode (URL, text, etc.)
            filename: Output filename (auto-generated if None)
            color: Foreground color (hex, e.g. '#000000')
            background: Background color (hex, e.g. '#FFFFFF')
            style: 'square', 'rounded', 'circle', 'gapped_square'
            size: Image size in pixels
            logo_path: Optional logo to embed in center
            border: Border size in modules
            error_correction: 'L', 'M', 'Q', 'H' (higher = more resilient)

        Returns:
            Path to generated PNG image
        """
        if not filename:
            import uuid
            filename = f"qr_{uuid.uuid4().hex[:8]}.png"

        if not filename.endswith(".png"):
            filename += ".png"

        output_path = os.path.join(self.output_dir, filename)

        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None,
            self._create_qr,
            data, output_path, color, background,
            style, size, logo_path, border, error_correction,
        )
        return output_path

    def _create_qr(
        self,
        data: str,
        output_path: str,
        color: str,
        background: str,
        style: str,
        size: int,
        logo_path: Optional[str],
        border: int,
        error_correction: str,
    ):
        try:
            import qrcode
            from qrcode.image.styledpil import StyledPilImage
            from qrcode.image.styles.moduledrawers.pil import (
                RoundedModuleDrawer,
                CircleModuleDrawer,
                GappedSquareModuleDrawer,
                SquareModuleDrawer,
            )
            from qrcode.constants import ERROR_CORRECT_H, ERROR_CORRECT_Q, ERROR_CORRECT_M, ERROR_CORRECT_L
            from PIL import Image

            ec_map = {
                "H": ERROR_CORRECT_H,
                "Q": ERROR_CORRECT_Q,
                "M": ERROR_CORRECT_M,
                "L": ERROR_CORRECT_L,
            }
            drawer_map = {
                "rounded": RoundedModuleDrawer(),
                "circle": CircleModuleDrawer(),
                "gapped_square": GappedSquareModuleDrawer(),
                "square": SquareModuleDrawer(),
            }

            qr = qrcode.QRCode(
                error_correction=ec_map.get(error_correction, ERROR_CORRECT_H),
                box_size=10,
                border=border,
            )
            qr.add_data(data)
            qr.make(fit=True)

            drawer = drawer_map.get(style, SquareModuleDrawer())
            img = qr.make_image(
                image_factory=StyledPilImage,
                module_drawer=drawer,
                fill_color=color,
                back_color=background,
            ).convert("RGB")

            # Embed logo if provided
            if logo_path and os.path.exists(logo_path):
                try:
                    logo = Image.open(logo_path).convert("RGBA")
                    qr_size = img.size[0]
                    logo_size = qr_size // 5
                    logo = logo.resize((logo_size, logo_size), Image.LANCZOS)
                    pos = ((qr_size - logo_size) // 2, (qr_size - logo_size) // 2)
                    img.paste(logo, pos, mask=logo.split()[3])
                except Exception as e:
                    logger.warning(f"Logo embed failed: {e}")

            # Resize to desired size
            img = img.resize((size, size), Image.LANCZOS)
            img.save(output_path, "PNG", optimize=True)

        except ImportError:
            self._create_qr_basic(data, output_path, size)

    def _create_qr_basic(self, data: str, output_path: str, size: int):
        """Fallback using basic qrcode without PIL styling."""
        try:
            import qrcode
            qr = qrcode.QRCode(border=4)
            qr.add_data(data)
            qr.make(fit=True)
            img = qr.make_image(fill_color="black", back_color="white")
            img.save(output_path)
        except ImportError:
            raise ImportError(
                "QR kod yasash uchun: pip install qrcode[pil]"
            )

    async def wifi(
        self,
        ssid: str,
        password: str,
        security: str = "WPA",
        hidden: bool = False,
        **kwargs,
    ) -> str:
        """
        Generate a WiFi QR code.

        Args:
            ssid: Network name
            password: WiFi password
            security: 'WPA', 'WEP', or 'nopass'
            hidden: Whether network is hidden
        """
        h = "true" if hidden else "false"
        wifi_data = f"WIFI:T:{security};S:{ssid};P:{password};H:{h};;"
        return await self.generate(wifi_data, filename=f"wifi_{ssid}.png", **kwargs)

    async def contact(
        self,
        name: str,
        phone: Optional[str] = None,
        email: Optional[str] = None,
        url: Optional[str] = None,
        **kwargs,
    ) -> str:
        """Generate a vCard QR code."""
        lines = ["BEGIN:VCARD", "VERSION:3.0", f"FN:{name}"]
        if phone:
            lines.append(f"TEL:{phone}")
        if email:
            lines.append(f"EMAIL:{email}")
        if url:
            lines.append(f"URL:{url}")
        lines.append("END:VCARD")
        vcard = "\n".join(lines)
        return await self.generate(vcard, filename=f"contact_{name}.png", **kwargs)

    async def bulk_generate(
        self,
        items: list,
        color: str = "#000000",
        background: str = "#FFFFFF",
        style: str = "square",
    ) -> list:
        """
        Generate multiple QR codes concurrently.

        Args:
            items: List of (data, filename) tuples or just strings

        Returns:
            List of output paths
        """
        tasks = []
        for item in items:
            if isinstance(item, tuple):
                data, fname = item
                tasks.append(self.generate(data, filename=fname, color=color, background=background, style=style))
            else:
                tasks.append(self.generate(item, color=color, background=background, style=style))

        return await asyncio.gather(*tasks)

    def cleanup(self, *paths: str):
        """Delete generated QR code files."""
        for path in paths:
            try:
                if path and os.path.exists(path):
                    os.remove(path)
            except Exception as e:
                logger.warning(f"Cleanup failed: {e}")
