from __future__ import annotations

import base64
import io
import logging
import os
import re
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)


class DrawingCadDwgMixin:
    @staticmethod
    def extract_dwg_text_and_preview(file_path: Path | str) -> list[dict[str, Any]]:
        """Extract strings and high-resolution CAD preview from binary AutoCAD DWG file (100% Watermark-Free)."""
        from PIL import Image

        from app.modules.takeoff.application.cad_converter_service import CadConverterService
        from app.modules.takeoff.application.vietnamese_cad_font_transcoder import (
            VietnameseCadFontTranscoder,
        )

        from .cad_blueprint import DrawingCadBlueprintMixin

        file_path = Path(file_path)
        extracted_lines: list[str] = []

        # 1. High-precision extraction via LibreDWG/ODA + ezdxf
        try:
            dxf_path = CadConverterService.convert_dwg_to_dxf(str(file_path))
            if dxf_path and os.path.exists(dxf_path):
                raw_texts = CadConverterService.extract_texts_from_dxf(dxf_path)
                for t in raw_texts:
                    clean = VietnameseCadFontTranscoder.auto_transcode_cad_text(t)
                    if clean and len(clean) > 2:
                        extracted_lines.append(clean)
        except Exception as dxf_err:
            logger.warning("[TAKEOFF] DXF text extraction error: %s", dxf_err)

        # 2. Binary fallback scan for any missing text
        try:
            with open(file_path, "rb") as f:
                content = f.read()
            utf16_matches = re.findall(b"(?:[\x20-\x7e\xa0-\xff]\x00){3,}", content)
            for raw in utf16_matches[:8000]:
                try:
                    s = raw.decode("utf-16le", errors="ignore").strip()
                    if (
                        len(s) > 2
                        and not s.startswith("<?xml")
                        and not s.startswith("<Product")
                    ):
                        clean = VietnameseCadFontTranscoder.auto_transcode_cad_text(s)
                        if clean and len(clean) > 2:
                            extracted_lines.append(clean)
                except Exception:
                    pass
        except Exception as bin_err:
            logger.warning("[TAKEOFF] DWG binary scan error: %s", bin_err)

        # 3. Clean rendering (Watermark-Free & High Speed)
        static_drawings_dir = (
            Path(__file__).resolve().parents[2] / "static" / "drawings"
        )
        static_drawings_dir.mkdir(parents=True, exist_ok=True)
        master_png = static_drawings_dir / f"{file_path.stem}_master.png"
        master_svg = static_drawings_dir / f"{file_path.stem}_master.svg"

        overview_b64 = ""
        if master_svg.exists() and master_svg.stat().st_size > 1000:
            logger.info(f"[CAD] Reusing cached master SVG preview: {master_svg}")
            with open(master_svg, "rb") as f:
                overview_b64 = base64.b64encode(f.read()).decode("utf-8")
        elif master_png.exists() and master_png.stat().st_size > 1000:
            logger.info(f"[CAD] Reusing cached master PNG preview: {master_png}")
            with open(master_png, "rb") as f:
                overview_b64 = base64.b64encode(f.read()).decode("utf-8")
        else:
            render_ok = CadConverterService.render_clean_dwg_preview(
                str(file_path), str(master_png), dpi=150
            )
            if master_svg.exists():
                with open(master_svg, "rb") as f:
                    overview_b64 = base64.b64encode(f.read()).decode("utf-8")
            elif render_ok and master_png.exists():
                with open(master_png, "rb") as f:
                    overview_b64 = base64.b64encode(f.read()).decode("utf-8")
            else:
                overview_b64 = DrawingCadBlueprintMixin.render_high_res_cad_blueprint(
                    file_path=file_path,
                    drawing_title=f"Bản vẽ: {file_path.stem}",
                    drawing_code=f"DWG-{file_path.stem[:15].upper()}",
                    dpi=300,
                    facecolor="#080d1a",
                )
                try:
                    with open(master_png, "wb") as f:
                        f.write(base64.b64decode(overview_b64))
                except Exception:
                    pass

        seen = set()
        deduped: list[str] = []
        for line in extracted_lines:
            line_str = line.strip()
            if line_str and line_str not in seen:
                seen.add(line_str)
                deduped.append(line_str)

        full_text = "\n".join(deduped)
        primary_image_url = (
            f"/static/drawings/{master_svg.name}"
            if master_svg.exists()
            else f"/static/drawings/{master_png.name}"
        )
        primary_mime = "image/svg+xml" if master_svg.exists() else "image/png"

        pages = [
            {
                "page_number": 0,
                "title": "Toàn cảnh bản vẽ (Overview)",
                "image_url": primary_image_url,
                "image_base64": overview_b64,
                "mime_type": primary_mime,
                "text_layer": full_text[:48000],
            }
        ]

        if master_svg.exists() and master_svg.stat().st_size > 1000:
            try:
                with open(master_svg, "r", encoding="utf-8", errors="ignore") as f_m:
                    svg_raw = f_m.read()

                # Text transcoding
                def _sub_text(m):
                    prefix = m.group(1)
                    raw_inner = m.group(2)
                    suffix = m.group(3)
                    unescaped = html.unescape(raw_inner)
                    cleaned = VietnameseCadFontTranscoder.clean_autocad_mtext(unescaped)
                    unicode_str = VietnameseCadFontTranscoder.auto_transcode_cad_text(
                        cleaned
                    )
                    safe_xml = (
                        unicode_str.replace("&", "&amp;")
                        .replace("<", "&lt;")
                        .replace(">", "&gt;")
                    )
                    return f"{prefix}{safe_xml}{suffix}"

                transcoded_svg = re.sub(
                    r"(<text[^>]*>)([^<]+)(</text>)", _sub_text, svg_raw
                )

                # Inject clean non-blobbing CAD vector styling
                css_style = """
<style>
  path, line, polyline {
    vector-effect: non-scaling-stroke !important;
    stroke: #38bdf8 !important;
    stroke-width: 1px !important;
  }
  text {
    font-family: 'Inter', 'Segoe UI', Arial, sans-serif !important;
    fill: #f8fafc !important;
    font-weight: 500 !important;
  }
  svg {
    background-color: #080d1a !important;
  }
</style>
"""
                styled_svg = re.sub(
                    r"(<svg[^>]*>)", r"\1\n" + css_style, transcoded_svg, count=1
                )

                # 6 Real spatial sheets + 1 Overview
                sheet_definitions = [
                    (
                        "Trang 1: Tổng mặt bằng & Quy hoạch sân",
                        "40000.0 440000.0 100000.0 110000.0",
                    ),
                    (
                        "Trang 2: Mặt bằng Kiến trúc, Kết cấu mái & Vì kèo NVH",
                        "170000.0 450000.0 100000.0 120000.0",
                    ),
                    (
                        "Trang 3: Chi tiết Cửa Xingfa, Cột, Tam cấp & Lan can",
                        "170000.0 570000.0 100000.0 175000.0",
                    ),
                    (
                        "Trang 4: Hệ thống Kỹ thuật Điện & Chống sét mái",
                        "270000.0 450000.0 95000.0 120000.0",
                    ),
                    (
                        "Trang 5: Nhà vệ sinh (WC), Bể tự hoại & Móng WC",
                        "420000.0 440000.0 65000.0 80000.0",
                    ),
                    (
                        "Trang 6: Thoát nước ngoài sân, Hố ga & Mương rãnh",
                        "520000.0 440000.0 115000.0 200000.0",
                    ),
                ]

                # Update master preview SVG
                master_vb = "40000.0 440000.0 590000.0 305000.0"
                master_svg_content = re.sub(
                    r'viewBox="[^"]+"', f'viewBox="{master_vb}"', styled_svg, count=1
                )
                with open(master_svg, "w", encoding="utf-8") as f_mst:
                    f_mst.write(master_svg_content)

                pages = [
                    {
                        "page_number": 0,
                        "title": "Toàn cảnh bản vẽ (Overview)",
                        "image_url": f"/static/drawings/{master_svg.name}",
                        "image_base64": "",
                        "mime_type": "image/svg+xml",
                        "text_layer": full_text[:48000],
                        "viewBox": master_vb,
                    }
                ]

                for i, (title, vb) in enumerate(sheet_definitions):
                    page_svg = re.sub(
                        r'viewBox="[^"]+"', f'viewBox="{vb}"', styled_svg, count=1
                    )
                    page_svg_path = (
                        static_drawings_dir / f"{file_path.stem}_p{i + 1}.svg"
                    )
                    with open(page_svg_path, "w", encoding="utf-8") as f_p:
                        f_p.write(page_svg)

                    pages.append(
                        {
                            "page_number": i + 1,
                            "title": title,
                            "image_url": f"/static/drawings/{page_svg_path.name}",
                            "image_base64": "",
                            "mime_type": "image/svg+xml",
                            "text_layer": full_text[:48000],
                            "viewBox": vb,
                        }
                    )
            except Exception as e:
                logger.warning("[TAKEOFF] Multi-page SVG split error: %s", e)
        elif master_png.exists() and master_png.stat().st_size > 1000:
            try:
                img = Image.open(master_png)
                w, h = img.size
                num_panels = 4
                panel_w = w / num_panels
                page_titles = [
                    "Trang 1: Mặt bằng kiến trúc & Hiện trạng",
                    "Trang 2: Mặt bằng kết cấu móng & Bố trí cột",
                    "Trang 3: Chi tiết Dầm, Giằng, Sê nô & Cửa",
                    "Trang 4: Mặt bằng Mái, Vì kèo & Thống kê cốt thép",
                ]
                for i in range(num_panels):
                    left = int(i * panel_w)
                    right = int((i + 1) * panel_w)
                    cropped = img.crop((left, 0, right, h))
                    page_png_path = (
                        static_drawings_dir / f"{file_path.stem}_p{i + 1}.png"
                    )
                    cropped.save(page_png_path, format="PNG")

                    buf = io.BytesIO()
                    cropped.save(buf, format="PNG")
                    page_b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
                    pages.append(
                        {
                            "page_number": i + 1,
                            "title": page_titles[i]
                            if i < len(page_titles)
                            else f"Trang {i + 1} (Phân khu A3)",
                            "image_url": f"/static/drawings/{page_png_path.name}",
                            "image_base64": page_b64,
                            "mime_type": "image/png",
                            "text_layer": full_text[:48000],
                        }
                    )
            except Exception as e:
                logger.warning("[TAKEOFF] Multi-page A3 split error: %s", e)

        return pages

    @staticmethod
    def render_dxf_to_images(file_path: Path, dpi: int = 150) -> list[dict[str, Any]]:
        """Render DXF drawing to high-resolution CAD images with text extraction and Vietnamese font transcoding."""
        from app.modules.takeoff.application.cad_converter_service import CadConverterService
        from app.modules.takeoff.application.vietnamese_cad_font_transcoder import (
            VietnameseCadFontTranscoder,
        )

        file_path = Path(file_path)
        static_drawings_dir = (
            Path(__file__).resolve().parents[2] / "static" / "drawings"
        )
        static_drawings_dir.mkdir(parents=True, exist_ok=True)
        master_png = static_drawings_dir / f"{file_path.stem}_master.png"

        extracted_lines: list[str] = []
        try:
            raw_texts = CadConverterService.extract_texts_from_dxf(str(file_path))
            for t in raw_texts:
                clean = VietnameseCadFontTranscoder.auto_transcode_cad_text(t)
                if clean and len(clean.strip()) > 0:
                    extracted_lines.append(clean.strip())
        except Exception as dxf_err:
            logger.warning(
                "[TAKEOFF] DXF text extraction error in render_dxf_to_images: %s",
                dxf_err,
            )

        seen = set()
        deduped: list[str] = []
        for line in extracted_lines:
            if line and line not in seen:
                seen.add(line)
                deduped.append(line)
        full_text = "\n".join(deduped)

        from .cad_blueprint import DrawingCadBlueprintMixin

        b64 = DrawingCadBlueprintMixin.render_high_res_cad_blueprint(
            file_path=file_path,
            drawing_title=f"Bản vẽ DXF: {file_path.stem}",
            drawing_code=f"DXF-{file_path.stem[:15].upper()}",
            dpi=dpi,
            facecolor="#080d1a",
        )
        try:
            with open(master_png, "wb") as f:
                f.write(base64.b64decode(b64))
        except Exception:
            pass

        return [
            {
                "page_number": 1,
                "title": f"Bản vẽ DXF: {file_path.stem}",
                "image_url": f"/static/drawings/{master_png.name}",
                "image_base64": b64,
                "mime_type": "image/png",
                "text_layer": full_text[:6000],
            }
        ]
