# app/modules/hosting/services/poc_builder_service.py
"""
POC Builder Service — creates a near-final multi-page website from
a prospect + industry template.

Flow:
1. Load prospect data (scraped content, contacts)
2. Load industry template (pages, theme)
3. Create HostedSite + Store via hosted_site_service
4. Populate CMS ContentPages from template, replacing {{placeholders}}
   with prospect data
5. Apply StoreTheme from template
6. Result: a previewable site at {subdomain}.hostwizard.lu
"""

import json
import logging
import re
from datetime import UTC, datetime

from sqlalchemy.orm import Session

from app.modules.hosting.services.hosted_site_service import hosted_site_service
from app.modules.hosting.services.template_service import template_service

logger = logging.getLogger(__name__)


class PocBuilderService:
    """Builds POC sites from prospect data + industry templates."""

    def build_poc(
        self,
        db: Session,
        prospect_id: int,
        template_id: str,
        merchant_id: int | None = None,
        site_id: int | None = None,
    ) -> dict:
        """Build a complete POC site from prospect data and a template.

        If site_id is given, populates the existing site's store with CMS
        content. Otherwise creates a new HostedSite + Store.

        Returns dict with hosted_site, store, pages_created, theme_applied.
        """
        from app.modules.prospecting.models import Prospect

        # 1. Load prospect
        prospect = db.query(Prospect).filter(Prospect.id == prospect_id).first()
        if not prospect:
            from app.modules.prospecting.exceptions import ProspectNotFoundException

            raise ProspectNotFoundException(str(prospect_id))

        # 2. Load template
        template = template_service.get_template(template_id)
        if not template:
            raise ValueError(f"Template '{template_id}' not found")

        # 3. Build placeholder context from prospect data
        context = self._build_context(prospect)

        # 4. Use existing site or create new one
        if site_id:
            site = hosted_site_service.get_by_id(db, site_id)
        else:
            site_data = {
                "business_name": context["business_name"],
                "domain_name": prospect.domain_name,
                "prospect_id": prospect_id,
                "contact_email": context.get("email"),
                "contact_phone": context.get("phone"),
            }
            if merchant_id:
                site_data["merchant_id"] = merchant_id
            site = hosted_site_service.create(db, site_data)

        # 5. Get the hosting platform_id from the store
        from app.modules.tenancy.models import StorePlatform

        store_platform = (
            db.query(StorePlatform)
            .filter(StorePlatform.store_id == site.store_id)
            .first()
        )
        platform_id = store_platform.platform_id if store_platform else None

        if not platform_id:
            logger.warning("No platform found for store %d", site.store_id)

        # 6. Populate CMS ContentPages from template
        pages_created = 0
        if platform_id:
            pages_created = self._create_pages(db, site.store_id, platform_id, template, context)

        # 7. Apply StoreTheme
        theme_applied = self._apply_theme(db, site.store_id, template)

        # 8. Mark POC ready
        hosted_site_service.mark_poc_ready(db, site.id)

        db.flush()
        logger.info(
            "POC built for prospect %d: site=%d, store=%d, %d pages, template=%s",
            prospect_id, site.id, site.store_id, pages_created, template_id,
        )

        return {
            "hosted_site_id": site.id,
            "store_id": site.store_id,
            "pages_created": pages_created,
            "theme_applied": theme_applied,
            "template_id": template_id,
            "subdomain": site.store.subdomain if site.store else None,
        }

    def _build_context(self, prospect) -> dict:
        """Build placeholder replacement context from prospect data."""
        # Base context
        context = {
            "business_name": prospect.business_name or prospect.domain_name or "My Business",
            "domain": prospect.domain_name or "",
            "city": prospect.city or "",
            "address": "",
            "email": "",
            "phone": "",
            "meta_description": "",
            "about_paragraph": "",
        }

        # From contacts
        contacts = prospect.contacts or []
        for c in contacts:
            if c.contact_type == "email" and not context["email"]:
                context["email"] = c.value
            elif c.contact_type == "phone" and not context["phone"]:
                context["phone"] = c.value
            elif c.contact_type == "address" and not context["address"]:
                context["address"] = c.value

        # From scraped content
        if prospect.scraped_content_json:
            try:
                scraped = json.loads(prospect.scraped_content_json)
                if scraped.get("meta_description"):
                    context["meta_description"] = scraped["meta_description"]
                if scraped.get("paragraphs"):
                    context["about_paragraph"] = scraped["paragraphs"][0]
                    # Build rich content from scraped paragraphs for page bodies
                    context["scraped_paragraphs_html"] = "\n".join(
                        f"<p>{p}</p>" for p in scraped["paragraphs"][:5]
                    )
                if scraped.get("headings"):
                    if not prospect.business_name:
                        context["business_name"] = scraped["headings"][0]
                    # Use second heading as tagline if available
                    if len(scraped["headings"]) > 1:
                        context["tagline"] = scraped["headings"][1]
            except (json.JSONDecodeError, KeyError):
                pass

        # From prospect fields
        if prospect.city:
            context["city"] = prospect.city
        elif context["address"]:
            # Try to extract city from address (last word after postal code)
            parts = context["address"].split()
            if len(parts) >= 2:
                context["city"] = parts[-1]

        return context

    def _replace_placeholders(self, text: str, context: dict) -> str:
        """Replace {{placeholder}} variables in text with context values."""
        if not text:
            return text

        def replacer(match):
            key = match.group(1).strip()
            return context.get(key, match.group(0))

        return re.sub(r"\{\{(\w+)\}\}", replacer, text)

    def _replace_in_structure(self, data, context: dict):
        """Recursively replace placeholders in a nested dict/list structure."""
        if isinstance(data, str):
            return self._replace_placeholders(data, context)
        if isinstance(data, dict):
            return {k: self._replace_in_structure(v, context) for k, v in data.items()}
        if isinstance(data, list):
            return [self._replace_in_structure(item, context) for item in data]
        return data

    def _create_pages(self, db: Session, store_id: int, platform_id: int, template: dict, context: dict) -> int:
        """Create CMS ContentPages from template page definitions."""
        from app.modules.cms.models.content_page import ContentPage

        count = 0
        for page_def in template.get("pages", []):
            slug = page_def.get("slug", "")
            if not slug:
                continue

            # Replace placeholders in all text fields
            page_data = self._replace_in_structure(page_def, context)

            # Build content from content_translations if present
            content = page_data.get("content", "")
            content_translations = page_data.get("content_translations")
            if content_translations and not content:
                content = next(iter(content_translations.values()), "")

            # Enrich with scraped paragraphs (append to template content)
            scraped_html = context.get("scraped_paragraphs_html", "")
            if scraped_html and slug in ("about", "services", "projects"):
                content = content + "\n" + scraped_html if content else scraped_html
                if content_translations:
                    for lang_code in content_translations:
                        content_translations[lang_code] = (
                            content_translations[lang_code] + "\n" + scraped_html
                        )

            page = ContentPage(
                platform_id=platform_id,
                store_id=store_id,
                is_platform_page=False,
                slug=slug,
                title=page_data.get("title", slug.title()),
                content=content or f"<p>{slug.title()} page content</p>",
                content_format="html",
                template=page_data.get("template", "default"),
                sections=page_data.get("sections"),
                title_translations=page_data.get("title_translations"),
                content_translations=content_translations,
                meta_description=context.get("meta_description"),
                is_published=page_data.get("is_published", True),
                published_at=datetime.now(UTC) if page_data.get("is_published", True) else None,
                show_in_header=page_data.get("show_in_header", False),
                show_in_footer=page_data.get("show_in_footer", False),
            )
            db.add(page)
            count += 1

        db.flush()
        return count

    def _apply_theme(self, db: Session, store_id: int, template: dict) -> bool:
        """Apply the template's theme to the store."""
        from app.modules.cms.models.store_theme import StoreTheme

        theme_data = template.get("theme")
        if not theme_data:
            return False

        # Check if store already has a theme
        existing = db.query(StoreTheme).filter(StoreTheme.store_id == store_id).first()
        if existing:
            # Update existing
            theme = existing
        else:
            theme = StoreTheme(store_id=store_id)
            db.add(theme)

        colors = theme_data.get("colors", {})
        theme.theme_name = theme_data.get("theme_name", "default")
        theme.colors = colors
        theme.font_family_heading = theme_data.get("font_family_heading", "Inter")
        theme.font_family_body = theme_data.get("font_family_body", "Inter")
        theme.layout_style = theme_data.get("layout_style", "grid")
        theme.header_style = theme_data.get("header_style", "fixed")

        db.flush()
        return True


poc_builder_service = PocBuilderService()
