"""
WikiToPDF - Search Wikipedia and convert articles to PDF.
"""

import asyncio
import os
import re
import tempfile
from typing import Dict, List, Optional
import logging

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


class WikiResult:
    def __init__(self, data: Dict):
        self.title: str = data.get("title", "")
        self.summary: str = data.get("summary", "")
        self.url: str = data.get("url", "")
        self.content: str = data.get("content", "")
        self.images: List[str] = data.get("images", [])
        self.sections: List[Dict] = data.get("sections", [])

    def preview(self, max_chars: int = 300) -> str:
        text = self.summary[:max_chars]
        if len(self.summary) > max_chars:
            text += "..."
        return (
            f"📖 <b>{self.title}</b>\n\n"
            f"{text}\n\n"
            f"🔗 <a href='{self.url}'>Wikipedia</a>"
        )


class WikiToPDF:
    """
    Search Wikipedia and generate PDF documents from articles.

    Supports: English, Russian, Uzbek, and all other Wikipedia languages.

    Example:
        wiki = WikiToPDF(language="uz")  # uz=o'zbekcha, en=english, ru=russian

        @bot.command("wiki")
        async def wiki_cmd(ctx):
            if not ctx.args:
                await ctx.reply("Qidiruv so'zini kiriting!\nMisol: /wiki Python")
                return

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

            result = await wiki.search(query)
            if not result:
                await ctx.reply("❌ Hech narsa topilmadi.")
                return

            await ctx.reply(result.preview())
            await ctx.upload_document()

            pdf_path = await wiki.to_pdf(result)
            await ctx.send_document(pdf_path, caption=f"📄 {result.title}")
            wiki.cleanup(pdf_path)
    """

    WIKIPEDIA_API = "https://{lang}.wikipedia.org/w/api.php"

    def __init__(self, language: str = "en", output_dir: Optional[str] = None):
        self.language = language
        self.output_dir = output_dir or tempfile.gettempdir()
        os.makedirs(self.output_dir, exist_ok=True)

    async def search(self, query: str, sentences: int = 10) -> Optional[WikiResult]:
        """
        Search Wikipedia and return the best matching article.

        Args:
            query: Search term
            sentences: Number of sentences in summary

        Returns:
            WikiResult or None if not found
        """
        import httpx

        api_url = self.WIKIPEDIA_API.format(lang=self.language)

        params = {
            "action": "query",
            "format": "json",
            "list": "search",
            "srsearch": query,
            "srlimit": 1,
            "utf8": 1,
        }

        async with httpx.AsyncClient(timeout=15) as client:
            try:
                resp = await client.get(api_url, params=params)
                data = resp.json()
                search_results = data.get("query", {}).get("search", [])
                if not search_results:
                    return None

                title = search_results[0]["title"]
                return await self.get_article(title, sentences=sentences)

            except Exception as e:
                logger.error(f"Wikipedia search error: {e}")
                return None

    async def get_article(self, title: str, sentences: int = 10) -> Optional[WikiResult]:
        """Get a specific Wikipedia article by title."""
        import httpx

        api_url = self.WIKIPEDIA_API.format(lang=self.language)

        params = {
            "action": "query",
            "format": "json",
            "titles": title,
            "prop": "extracts|info|images",
            "exintro": 0,
            "explaintext": 1,
            "exsentences": sentences,
            "inprop": "url",
            "utf8": 1,
        }

        async with httpx.AsyncClient(timeout=15) as client:
            try:
                resp = await client.get(api_url, params=params)
                data = resp.json()
                pages = data.get("query", {}).get("pages", {})
                page = next(iter(pages.values()))

                if "missing" in page:
                    return None

                full_params = {**params, "exintro": 0, "exsentences": 100}
                resp2 = await client.get(api_url, params=full_params)
                full_data = resp2.json()
                full_pages = full_data.get("query", {}).get("pages", {})
                full_page = next(iter(full_pages.values()))
                full_content = full_page.get("extract", "")

                intro_params = {**params, "exintro": 1}
                resp3 = await client.get(api_url, params=intro_params)
                intro_data = resp3.json()
                intro_pages = intro_data.get("query", {}).get("pages", {})
                intro_page = next(iter(intro_pages.values()))
                intro = intro_page.get("extract", "")[:500]

                return WikiResult({
                    "title": page.get("title", title),
                    "summary": intro,
                    "url": page.get("fullurl", f"https://{self.language}.wikipedia.org/wiki/{title}"),
                    "content": full_content,
                    "images": [],
                })

            except Exception as e:
                logger.error(f"Wikipedia article fetch error: {e}")
                return None

    async def to_pdf(
        self,
        result: WikiResult,
        filename: Optional[str] = None,
        include_url: bool = True,
    ) -> str:
        """
        Convert WikiResult to a PDF file.

        Args:
            result: WikiResult object
            filename: Custom output filename
            include_url: Include article URL in footer

        Returns:
            Path to generated PDF file
        """
        if not filename:
            safe_title = re.sub(r'[^\w\s-]', '', result.title)[:50].strip()
            filename = f"wiki_{safe_title}.pdf"

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

        loop = asyncio.get_event_loop()
        await loop.run_in_executor(
            None, self._generate_pdf, result, output_path, include_url
        )
        return output_path

    def _generate_pdf(self, result: WikiResult, output_path: str, include_url: bool):
        """Generate PDF synchronously."""
        try:
            from reportlab.lib.pagesizes import A4
            from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
            from reportlab.lib.units import cm
            from reportlab.lib import colors
            from reportlab.platypus import (
                SimpleDocTemplate, Paragraph, Spacer, HRFlowable
            )
            from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
            from reportlab.pdfbase import pdfmetrics
            from reportlab.pdfbase.ttfonts import TTFont

            doc = SimpleDocTemplate(
                output_path,
                pagesize=A4,
                leftMargin=2 * cm,
                rightMargin=2 * cm,
                topMargin=2 * cm,
                bottomMargin=2 * cm,
            )

            styles = getSampleStyleSheet()

            title_style = ParagraphStyle(
                "ZentelTitle",
                parent=styles["Title"],
                fontSize=22,
                spaceAfter=12,
                textColor=colors.HexColor("#1a237e"),
                alignment=TA_CENTER,
            )

            header_style = ParagraphStyle(
                "ZentelHeader",
                parent=styles["Heading2"],
                fontSize=13,
                spaceBefore=14,
                spaceAfter=6,
                textColor=colors.HexColor("#283593"),
            )

            body_style = ParagraphStyle(
                "ZentelBody",
                parent=styles["Normal"],
                fontSize=10,
                leading=15,
                spaceAfter=8,
                alignment=TA_JUSTIFY,
            )

            meta_style = ParagraphStyle(
                "ZentelMeta",
                parent=styles["Normal"],
                fontSize=8,
                textColor=colors.grey,
                alignment=TA_CENTER,
            )

            story = []

            # Zentel watermark
            story.append(Paragraph("Generated by Zentel 1.0.0", meta_style))
            story.append(Spacer(1, 0.3 * cm))
            story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor("#3949ab")))
            story.append(Spacer(1, 0.5 * cm))

            # Title
            story.append(Paragraph(result.title, title_style))
            story.append(Spacer(1, 0.3 * cm))

            # URL
            if include_url and result.url:
                story.append(
                    Paragraph(f'<link href="{result.url}">{result.url}</link>', meta_style)
                )
                story.append(Spacer(1, 0.4 * cm))

            story.append(HRFlowable(width="100%", thickness=0.5, color=colors.lightgrey))
            story.append(Spacer(1, 0.5 * cm))

            # Content
            content = result.content or result.summary
            paragraphs = [p.strip() for p in content.split("\n") if p.strip()]

            for para in paragraphs:
                # Detect section headers (short lines, often all-caps or titled)
                if len(para) < 80 and not para.endswith(".") and len(para.split()) < 10:
                    story.append(Paragraph(para, header_style))
                else:
                    # Escape special chars for reportlab
                    safe = para.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
                    story.append(Paragraph(safe, body_style))

            story.append(Spacer(1, 0.5 * cm))
            story.append(HRFlowable(width="100%", thickness=0.5, color=colors.lightgrey))
            story.append(
                Paragraph(f"Wikipedia • {self.language.upper()} • Zentel 1.0.0", meta_style)
            )

            doc.build(story)

        except ImportError:
            # Fallback: plain text PDF using basic approach
            self._generate_simple_pdf(result, output_path)

    def _generate_simple_pdf(self, result: WikiResult, output_path: str):
        """Simple fallback PDF without reportlab styling."""
        try:
            from fpdf import FPDF

            pdf = FPDF()
            pdf.add_page()
            pdf.set_font("Arial", "B", 16)
            pdf.multi_cell(0, 10, result.title)
            pdf.ln(5)
            pdf.set_font("Arial", size=10)
            content = result.content or result.summary
            for line in content.split("\n"):
                if line.strip():
                    try:
                        pdf.multi_cell(0, 7, line.encode("latin-1", errors="replace").decode("latin-1"))
                    except Exception:
                        pdf.multi_cell(0, 7, "[...]")
            pdf.output(output_path)

        except ImportError:
            # Ultra fallback: write text file
            txt_path = output_path.replace(".pdf", ".txt")
            with open(txt_path, "w", encoding="utf-8") as f:
                f.write(f"{result.title}\n{'='*len(result.title)}\n\n")
                f.write(result.content or result.summary)
            raise RuntimeError(
                "PDF yaratish uchun 'reportlab' yoki 'fpdf2' kerak.\n"
                "pip install reportlab"
            )

    async def search_list(self, query: str, limit: int = 5) -> List[str]:
        """Return a list of article titles matching the query."""
        import httpx

        api_url = self.WIKIPEDIA_API.format(lang=self.language)
        params = {
            "action": "query",
            "format": "json",
            "list": "search",
            "srsearch": query,
            "srlimit": limit,
        }
        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.get(api_url, params=params)
            data = resp.json()
            results = data.get("query", {}).get("search", [])
            return [r["title"] for r in results]

    def cleanup(self, *paths: str):
        """Delete generated PDF 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}")
