#!/usr/bin/env python3
# Captura MULTIPLAS paginas do WP (localhost:8090) -> Buenas-New com fidelidade.
import os, re, html, shutil, hashlib
import requests
from urllib.parse import urljoin, urlparse

BASE = "http://localhost:8090/"
PROJ = "/Users/Bayerl/Documents/Projetos/Buenas-New"
ASSETS = os.path.join(PROJ, "public", "assets")
UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0 Safari/537.36"
S = requests.Session(); S.headers.update({"User-Agent": UA})
MAP = {}; FAIL = []

PAGES = [("/", "home", "Home - Buenas"),
         ("/sobre-nos/", "sobre-nos", "Sobre nós - Buenas"),
         ("/contato/", "contato", "Contato - Buenas")]

if os.path.isdir(ASSETS): shutil.rmtree(ASSETS)
os.makedirs(ASSETS, exist_ok=True)

def norm(u, base=BASE):
    if not u: return None
    u = u.strip()
    if u.startswith(("data:", "#", "mailto:", "tel:", "javascript:")): return None
    for d in ("https://www.buenascarnes.com.br","http://www.buenascarnes.com.br",
              "https://buenascarnes.com.br","http://buenascarnes.com.br"):
        u = u.replace(d, BASE.rstrip("/"))
    if u.startswith("//"): u = "https:" + u
    return urljoin(base, u)

def subdir_for(path, ctype=""):
    ext = os.path.splitext(urlparse(path).path)[1].lower()
    if ext == ".css" or "text/css" in ctype: return "css"
    if ext in (".woff",".woff2",".ttf",".otf",".eot"): return "fonts"
    if ext == ".js" or "javascript" in ctype: return "js"
    if ext in (".png",".jpg",".jpeg",".gif",".webp",".svg",".ico",".avif") or "image/" in ctype: return "img"
    return "misc"

def safe_name(url, sub):
    base = os.path.basename(urlparse(url).path) or "index"
    base = re.sub(r"[^A-Za-z0-9._-]", "_", base)
    root, ext = os.path.splitext(base)
    if sub == "css" and ext != ".css": ext = ".css"
    if sub == "fonts" and not ext: ext = ".woff2"
    h = hashlib.md5(url.encode()).hexdigest()[:8]
    return "%s.%s%s" % (root[:60] or "f", h, ext or "")

def download(url, process_css=True):
    n = norm(url)
    if not n: return url
    if n in MAP: return MAP[n]
    try:
        r = S.get(n, timeout=30)
        if r.status_code != 200: FAIL.append((r.status_code, n)); return url
    except Exception as e:
        FAIL.append((str(e)[:30], n)); return url
    ctype = r.headers.get("content-type", "")
    sub = subdir_for(n, ctype)
    name = safe_name(n, sub)
    local = "/assets/%s/%s" % (sub, name)
    MAP[n] = local
    outdir = os.path.join(ASSETS, sub); os.makedirs(outdir, exist_ok=True)
    data = r.content
    if sub == "css" and process_css:
        data = rewrite_css(r.text, n).encode("utf-8")
    with open(os.path.join(outdir, name), "wb") as f: f.write(data)
    return local

def rewrite_css(text, css_url):
    text = re.sub(r"url\(\s*['\"]?([^)'\"]+)['\"]?\s*\)",
                  lambda m: "url(%s)" % download(urljoin(css_url, m.group(1))), text)
    text = re.sub(r'@import\s+["\']([^"\']+)["\']',
                  lambda m: '@import "%s"' % download(urljoin(css_url, m.group(1))), text)
    return text

def rewrite_srcset(val, base=BASE):
    out = []
    for part in val.split(","):
        part = part.strip()
        if not part: continue
        bits = part.split()
        out.append(" ".join([download(urljoin(base, bits[0]))] + bits[1:]))
    return ", ".join(out)

Q = r'''=\s*(["'])(.*?)\1'''
def get_attr(tag, name):
    m = re.search(name + Q, tag, re.I); return m.group(2) if m else None
def set_attr(tag, name, val):
    val = val.replace('"', '&quot;')
    m = re.search(name + Q, tag, re.I)
    if m: return tag[:m.start()] + '%s="%s"' % (name, val) + tag[m.end():]
    return re.sub(r"\s*/?>\s*$", ' %s="%s">' % (name, val), tag, count=1)

def fix_motion_bg(text):
    pat = re.compile(
        r'(\.e-loop-item-\d+\s+\.elementor-element\.elementor-element-[0-9a-fA-F]+)'
        r'(?::not\([^)]*\))?[^{}]*?\.elementor-motion-effects-layer\s*\{\s*'
        r'background-image\s*:\s*(url\([^)]*\))\s*;?\s*\}', re.I)
    def add(m):
        return m.group(0) + ('%s{background-image:%s !important;background-size:cover !important;'
               'background-position:center center !important;background-repeat:no-repeat !important;}' % (m.group(1), m.group(2)))
    return pat.sub(add, text)

def process_page(path):
    url = urljoin(BASE, path)
    r = S.get(url, timeout=30); r.raise_for_status()
    doc = r.text

    def fix_lazy(m):
        tag = m.group(0)
        ds = get_attr(tag, "data-src") or get_attr(tag, "data-lazy-src")
        if ds: tag = set_attr(tag, "src", ds)
        dss = get_attr(tag, "data-srcset") or get_attr(tag, "data-lazysrcset")
        if dss: tag = set_attr(tag, "srcset", dss)
        return tag
    doc = re.sub(r"<img\b[^>]*>", fix_lazy, doc, flags=re.I)
    doc = doc.replace("elementor-invisible", "")

    def add_lazyloaded(m):
        q, cls = m.group(1), m.group(2)
        if "e-con" in cls and "e-lazyloaded" not in cls: cls = cls + " e-lazyloaded"
        return "class=%s%s%s" % (q, cls, q)
    doc = re.sub(r'class=(["\'])(.*?)\1', add_lazyloaded, doc, flags=re.I | re.S)

    def repl_link(m):
        tag = m.group(0); href = get_attr(tag, "href")
        rel = (get_attr(tag, "rel") or "").lower(); as_ = (get_attr(tag, "as") or "").lower()
        if not href: return tag
        if any(k in rel for k in ("stylesheet","icon","preload","apple-touch")) or as_ in ("style","font","image"):
            return set_attr(tag, "href", download(href))
        return tag
    doc = re.sub(r"<link\b[^>]*?>", repl_link, doc, flags=re.I)

    doc = re.sub(r"(<style\b[^>]*>)(.*?)(</style>)",
                 lambda m: m.group(1) + rewrite_css(m.group(2), BASE) + m.group(3), doc, flags=re.I|re.S)

    def repl_img(m):
        tag = m.group(0); src = get_attr(tag, "src")
        if src: tag = set_attr(tag, "src", download(src))
        ss = get_attr(tag, "srcset")
        if ss: tag = set_attr(tag, "srcset", rewrite_srcset(ss))
        return tag
    doc = re.sub(r"<img\b[^>]*>", repl_img, doc, flags=re.I)
    doc = re.sub(r"<source\b[^>]*>",
                 lambda m: set_attr(m.group(0), "srcset", rewrite_srcset(get_attr(m.group(0),"srcset"))) if get_attr(m.group(0),"srcset") else m.group(0),
                 doc, flags=re.I)

    def repl_inline_style(m):
        q, val = m.group(1), m.group(2)
        newv = re.sub(r"url\(\s*['\"]?([^)'\"]+)['\"]?\s*\)",
                      lambda mm: "url(%s)" % download(urljoin(BASE, mm.group(1))), val)
        return "style=%s%s%s" % (q, newv, q)
    doc = re.sub(r"style" + r'''=(["'])((?:(?!\1).)*url\((?:(?!\1).)*)\1''', repl_inline_style, doc, flags=re.I)

    doc = fix_motion_bg(doc)

    # counters do Elementor: animam de 0 ate data-to-value via JS -> fixa o valor final
    def fix_counter(m):
        open_tag, inner = m.group(1), m.group(3)
        tv = get_attr(open_tag, "data-to-value")
        return open_tag + (tv if tv else inner) + "</span>"
    doc = re.sub(r'(<span\b[^>]*?elementor-counter-number[^>]*?>)(.*?)(</span>)',
                 lambda m: m.group(1) + (get_attr(m.group(1), "data-to-value") or m.group(2)) + "</span>",
                 doc, flags=re.I | re.S)

    # coleta CSS inline
    page_css = []
    doc = re.sub(r"<style\b[^>]*>(.*?)</style>",
                 lambda m: (page_css.append(m.group(1)), "")[1], doc, flags=re.I|re.S)

    head_match = re.search(r"<head\b[^>]*>(.*?)</head>", doc, re.I|re.S)
    head = head_match.group(1) if head_match else ""
    links = re.findall(r"<link\b[^>]*?>", head, re.I)

    bm = re.search(r"<body\b([^>]*)>(.*?)</body>", doc, re.I|re.S)
    body_attrs = bm.group(1) if bm else ""
    body_inner = bm.group(2) if bm else doc
    bc = get_attr("<x " + body_attrs + ">", "class") or ""

    # links internos -> relativos (senao clicam de volta pro WP)
    for d in ("http://localhost:8090", "https://buenascarnes.com.br",
              "http://buenascarnes.com.br", "https://www.buenascarnes.com.br"):
        body_inner = body_inner.replace(d, "")
    # Cardápio (livemenu externo) abre em nova aba
    body_inner = body_inner.replace('<a href="https://livemenu.app',
                                    '<a target="_blank" rel="noopener" href="https://livemenu.app')
    return {"links": links, "css": page_css, "body": body_inner, "bodyclass": bc}

# ---- processa todas as paginas ----
all_links, seen_link = [], set()
all_css, seen_css = [], set()
os.makedirs(os.path.join(PROJ, "src"), exist_ok=True)
for path, slug, title in PAGES:
    print("capturando", path, "...")
    p = process_page(path)
    for lk in p["links"]:
        if lk not in seen_link: seen_link.add(lk); all_links.append(lk)
    for c in p["css"]:
        h = hashlib.md5(c.encode()).hexdigest()
        if h not in seen_css: seen_css.add(h); all_css.append(c)
    with open(os.path.join(PROJ, "src", "%s-body.html" % slug), "w") as f:
        f.write('<div class="%s">\n%s\n</div>' % (html.escape(p["bodyclass"], quote=True), p["body"]))

with open(os.path.join(ASSETS, "css", "_inline_captured.css"), "w") as f:
    f.write("\n".join(all_css))

with open(os.path.join(PROJ, "index.html"), "w") as f:
    f.write("""<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%s</title>
%s
<link rel="stylesheet" href="/assets/css/_inline_captured.css" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
""" % (PAGES[0][2], "\n".join(all_links)))

# ---- App.jsx com roteamento por pathname ----
def ident(slug):
    parts = re.split(r"[^a-zA-Z0-9]", slug)
    return parts[0] + "".join(w.capitalize() for w in parts[1:])
imports = "\n".join("import %s from './%s-body.html?raw'" % (ident(s), s) for _, s, _ in PAGES)
routes = []
titles = []
for path, slug, title in PAGES:
    key = path.rstrip("/") or "/"
    routes.append("  '%s': %s," % (path, ident(slug)))
    routes.append("  '%s': %s," % (key, ident(slug)))
    titles.append("  '%s': %r," % (path, title)); titles.append("  '%s': %r," % (key, title))
app = """%s

const ROUTES = {
%s
}
const TITLES = {
%s
}

export default function App() {
  const p = window.location.pathname
  const html = ROUTES[p] ?? ROUTES[p.endsWith('/') ? p.slice(0, -1) : p + '/'] ?? %s
  const t = TITLES[p] ?? TITLES[p.endsWith('/') ? p.slice(0, -1) : p + '/']
  if (t) document.title = t
  return <div dangerouslySetInnerHTML={{ __html: html }} />
}
""" % (imports, "\n".join(routes), "\n".join(titles), ident(PAGES[0][1]))
app_path = os.path.join(PROJ, "src", "App.jsx")
if not os.path.exists(app_path):
    with open(app_path, "w") as f:
        f.write(app)
else:
    print("App.jsx já existe — mantido (roteamento custom c/ blog)")

print("OK - paginas:", len(PAGES), "| assets:", len(MAP),
      "| CSS files:", sum(v.startswith("/assets/css") for v in MAP.values()),
      "IMG:", sum(v.startswith("/assets/img") for v in MAP.values()),
      "FONTS:", sum(v.startswith("/assets/fonts") for v in MAP.values()))
if FAIL:
    print("FALHAS (%d):" % len(FAIL))
    for e, u in FAIL[:10]: print("  ", e, u[:80])
