import os
import re
import time
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from urllib.parse import urljoin, urlparse

# ----------------------------
# Settings
# ----------------------------
BASE = "https://gfarmory.com"
START_URL = "https://gfarmory.com/firearms/"
FOLDER_NAME = "firearms"
os.makedirs(FOLDER_NAME, exist_ok=True)

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",
}
SESSION = requests.Session()
SESSION.headers.update(HEADERS)

SLEEP_BETWEEN_PRODUCTS = 1.2  # be polite
WAIT_LISTING = 4

# ----------------------------
# Selenium for listings
# ----------------------------
options = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(options=options)

def safe_name(text, maxlen=80):
    text = re.sub(r"\s+", "_", (text or "product").strip())
    text = re.sub(r"[^a-zA-Z0-9_.-]", "_", text)
    return text[:maxlen] if text else "product"

def get_soup_from_driver(url, sleep=WAIT_LISTING):
    print(f"🔄 Loading page: {url}")
    driver.get(url)
    time.sleep(sleep)  # allow any JS/lazyload
    return BeautifulSoup(driver.page_source, "html.parser")

def infer_extension(img_url, resp):
    path = urlparse(img_url).path
    ext = os.path.splitext(path)[1]
    if ext and len(ext) <= 5:
        return ext
    ct = resp.headers.get("Content-Type", "")
    if "image/" in ct:
        subtype = ct.split("image/")[-1].split(";")[0].strip().lower()
        if subtype in ("jpeg", "pjpeg"):
            return ".jpg"
        return "." + (subtype if subtype else "jpg")
    return ".jpg"

def download_image(img_url, basename, idx):
    try:
        r = SESSION.get(img_url, stream=True, timeout=30)
        r.raise_for_status()
        ext = infer_extension(img_url, r)
        filename = f"{basename}_{idx}{ext}"
        path = os.path.join(FOLDER_NAME, filename)
        with open(path, "wb") as f:
            for chunk in r.iter_content(1024):
                if chunk:
                    f.write(chunk)
        print(f"✅ Saved: {filename}")
    except Exception as e:
        print(f"❌ Failed: {img_url} -> {e}")

# ----------------------------
# Listing parsing (robust for BigCommerce)
# ----------------------------
def get_listing_product_links(soup):
    """
    BigCommerce markup varies; reliably collect any product URLs under /firearms/
    and skip the category root, pagination, compare, etc.
    """
    links = set()
    for a in soup.select("a[href]"):
        href = a.get("href")
        if not href:
            continue
        full = urljoin(BASE, href)
        # include only product detail pages under /firearms/
        if "/firearms/" in full:
            # skip the category root, pagination, query params for sorting, and non-detail anchors
            if full.rstrip("/") == START_URL.rstrip("/"):
                continue
            if "/page/" in full:
                continue
            # product detail pages usually look like /firearms/<slug>/
            segments = urlparse(full).path.strip("/").split("/")
            if len(segments) >= 2 and segments[0] == "firearms":
                links.add(full)
    return sorted(links)

def next_page_url(page_num):
    # pagination looks like /firearms/page/N/
    return START_URL if page_num == 1 else f"{START_URL}page/{page_num}/"

# ----------------------------
# Product page parsing (requests)
# ----------------------------
def get_soup_requests(url):
    r = SESSION.get(url, timeout=30)
    r.raise_for_status()
    return BeautifulSoup(r.text, "html.parser")

def collect_product_images(product_url):
    soup = get_soup_requests(product_url)

    # Title
    title_el = soup.select_one("h1, .productView-title, h1.product_title")
    title = title_el.get_text(strip=True) if title_el else "product"
    base = safe_name(title)

    images = []

    # BigCommerce usually has full-size anchors in the gallery that point to cdn*.bigcommerce.com
    for a in soup.select("a[href]"):
        href = a.get("href")
        if href and "bigcommerce.com" in href:
            full = urljoin(BASE, href)
            images.append(full)

    # Fallbacks: any product image elements
    if not images:
        for img in soup.select("img"):
            src = img.get("data-src") or img.get("src") or img.get("data-zoom-image")
            if src:
                full = urljoin(BASE, src)
                if "bigcommerce.com" in full or full.endswith((".jpg", ".jpeg", ".png", ".webp", ".gif")):
                    images.append(full)

    # Dedup (preserve order)
    seen = set()
    deduped = []
    for u in images:
        if u not in seen:
            deduped.append(u)
            seen.add(u)

    # Download all
    for i, u in enumerate(deduped, 1):
        download_image(u, base, i)

# ----------------------------
# Main crawl
# ----------------------------
try:
    page = 1
    while True:
        list_url = next_page_url(page)
        soup = get_soup_from_driver(list_url, sleep=WAIT_LISTING)

        product_links = get_listing_product_links(soup)
        if not product_links:
            print(f"⛔ No products found on page {page}. Stopping.")
            break

        print(f"🔍 Found {len(product_links)} product links on page {page}.")
        for purl in product_links:
            print(f"➡️  Scraping: {purl}")
            collect_product_images(purl)
            time.sleep(SLEEP_BETWEEN_PRODUCTS)

        page += 1

finally:
    driver.quit()

print(f"\n🎉 All images saved to: ./{FOLDER_NAME}/")
