import os
import io
import json
import base64
import logging
from typing import Optional

logger = logging.getLogger(__name__)

IMAGE_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.tiff'}
DOC_EXTENSIONS = {'.pdf', '.docx', '.doc', '.txt', '.md', '.rtf'}

IMAGE_CLASSIFICATIONS = [
    "hero_banner", "logo", "team_photo", "product_shot",
    "lifestyle", "background_texture", "icon_graphic",
    "testimonial_headshot", "gallery", "infographic",
    "section_separator", "other"
]

CLASSIFICATION_LABELS = {
    "hero_banner": "Hero Banner",
    "logo": "Logo / Brand Mark",
    "team_photo": "Team / People",
    "product_shot": "Product / Service",
    "lifestyle": "Lifestyle / Atmosphere",
    "background_texture": "Background / Texture",
    "icon_graphic": "Icon / Graphic",
    "testimonial_headshot": "Headshot / Portrait",
    "gallery": "Gallery / Showcase",
    "infographic": "Infographic / Chart",
    "section_separator": "Section Separator / Divider",
    "other": "Other",
}


def extract_text_from_file(file_path: str, filename: str) -> str:
    ext = os.path.splitext(filename)[1].lower()

    if ext == '.txt' or ext == '.md':
        with open(file_path, 'r', errors='ignore') as f:
            return f.read()

    elif ext == '.pdf':
        try:
            from PyPDF2 import PdfReader
            reader = PdfReader(file_path)
            text_parts = []
            for page in reader.pages:
                t = page.extract_text()
                if t:
                    text_parts.append(t)
            return "\n\n".join(text_parts)
        except Exception as e:
            logger.error(f"PDF extraction failed for {filename}: {e}")
            return f"[PDF extraction failed: {e}]"

    elif ext == '.docx':
        try:
            from docx import Document
            doc = Document(file_path)
            paragraphs = [p.text for p in doc.paragraphs if p.text.strip()]
            return "\n\n".join(paragraphs)
        except Exception as e:
            logger.error(f"DOCX extraction failed for {filename}: {e}")
            return f"[DOCX extraction failed: {e}]"

    elif ext == '.rtf':
        with open(file_path, 'r', errors='ignore') as f:
            return f.read()

    return ""


def classify_document_content(raw_text: str, domain: str, niche: str = "") -> dict:
    from app.services.llm import call_llm

    prompt = f"""Analyze this business/brand document for the domain "{domain}" (niche: {niche or 'unknown'}).

Extract and categorize the content into these fields. For each field, extract the EXACT relevant text from the document. If a field has no matching content, use null.

Return JSON:
{{
  "mission_statement": "exact mission statement text or null",
  "vision": "vision statement or null",
  "brand_voice": "description of tone/voice from doc or null",
  "core_values": ["value1", "value2", ...] or [],
  "key_phrases": ["important phrases that should appear on the website"],
  "about_content": "about us / company story text or null",
  "team_info": ["name - role - bio snippet", ...] or [],
  "testimonials": ["testimonial text - attribution", ...] or [],
  "product_services": ["product/service name - description", ...] or [],
  "target_audience": "described target audience or null",
  "competitive_advantages": ["advantage1", ...] or [],
  "contact_info": "any contact details found or null",
  "faq_content": [{{"q": "question", "a": "answer"}}, ...] or [],
  "statistics": ["stat1", "stat2", ...] or [],
  "pricing_info": "any pricing details or null",
  "additional_content": "any other important content that doesn't fit above categories"
}}

DOCUMENT TEXT:
{raw_text[:12000]}"""

    system = "You are a brand content analyst. Extract and categorize business document content into structured fields. Always respond with valid JSON."

    try:
        result = call_llm(prompt, system)
        if isinstance(result, str):
            if not result.strip():
                logger.warning(f"Document classification returned empty response for {domain}, using raw text fallback")
                return {
                    "additional_content": raw_text[:5000],
                    "about_content": raw_text[:2000],
                    "_source": "raw_fallback",
                }
            try:
                result = json.loads(result)
            except json.JSONDecodeError:
                logger.error(f"Document classification returned invalid JSON for {domain}: {result[:200]}")
                return {
                    "additional_content": raw_text[:5000],
                    "about_content": raw_text[:2000],
                    "_source": "json_parse_fallback",
                }
        if isinstance(result, dict):
            return result
        logger.warning(f"Document classification returned non-dict: {type(result)}")
        return {
            "additional_content": raw_text[:5000],
            "_source": "type_fallback",
        }
    except Exception as e:
        logger.error(f"Document classification failed: {e}")
        return {"error": str(e), "additional_content": raw_text[:3000]}


FILENAME_HINT_MAP = {
    "logo": "logo",
    "brand": "logo",
    "brandmark": "logo",
    "brand-logo": "logo",
    "icon": "icon_graphic",
    "section-icon": "icon_graphic",
    "favicon": "icon_graphic",
    "hero": "hero_banner",
    "banner": "hero_banner",
    "header": "hero_banner",
    "team": "team_photo",
    "staff": "team_photo",
    "headshot": "testimonial_headshot",
    "portrait": "testimonial_headshot",
    "avatar": "testimonial_headshot",
    "product": "product_shot",
    "lifestyle": "lifestyle",
    "background": "background_texture",
    "texture": "background_texture",
    "pattern": "background_texture",
    "bg": "background_texture",
    "gallery": "gallery",
    "infographic": "infographic",
    "chart": "infographic",
    "separator": "section_separator",
    "section-separator": "section_separator",
    "divider": "section_separator",
}


def _filename_hint(filename: str) -> str:
    name = os.path.splitext(filename)[0].lower()
    name = name.replace("-", " ").replace("_", " ").replace(".", " ")
    tokens = name.split()
    for token in tokens:
        if token in FILENAME_HINT_MAP:
            return FILENAME_HINT_MAP[token]
    for keyword, cls in FILENAME_HINT_MAP.items():
        if keyword in name:
            return cls
    return ""


def classify_image(file_path: str, filename: str, domain: str, niche: str = "") -> dict:
    from app.services.llm import call_llm_with_image

    try:
        with open(file_path, 'rb') as f:
            img_data = f.read()

        img_b64 = base64.b64encode(img_data).decode('utf-8')
        ext = os.path.splitext(filename)[1].lower()
        mime = {'.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png',
                '.gif': 'image/gif', '.webp': 'image/webp', '.bmp': 'image/bmp'}.get(ext, 'image/jpeg')

        filename_hint = _filename_hint(filename)

        result = call_llm_with_image(
            img_b64, mime, domain, niche,
            IMAGE_CLASSIFICATIONS,
            filename=filename,
            filename_hint=filename_hint
        )

        if filename_hint and result.get("classification") == "other":
            logger.info(f"Overriding 'other' classification to '{filename_hint}' based on filename '{filename}'")
            result["classification"] = filename_hint
            result["classification_source"] = "filename_override"

        return result
    except Exception as e:
        logger.error(f"Image classification failed for {filename}: {e}")
        return {
            "classification": "other",
            "tags": [],
            "description": f"Classification failed: {e}",
            "suggested_sections": []
        }


def build_brandkit_context(extracted: dict, image_classifications: list, domain: str) -> str:
    if not extracted and not image_classifications:
        return ""

    parts = ["\n== BRAND KIT (User-Provided Content — USE THIS AS PRIMARY SOURCE) =="]
    parts.append("The user has uploaded their own brand documents and images. PRIORITIZE this content over invented content.")
    parts.append("Use their exact phrases, mission statement, values, and tone wherever possible.")
    parts.append("Do NOT invent testimonials, team bios, or statistics if the user has provided real ones.\n")

    if extracted:
        if extracted.get("mission_statement"):
            parts.append(f"MISSION STATEMENT: {extracted['mission_statement']}")
        if extracted.get("vision"):
            parts.append(f"VISION: {extracted['vision']}")
        if extracted.get("brand_voice"):
            parts.append(f"BRAND VOICE/TONE: {extracted['brand_voice']}")
        if extracted.get("core_values"):
            parts.append(f"CORE VALUES: {', '.join(extracted['core_values'])}")
        if extracted.get("about_content"):
            parts.append(f"ABOUT / COMPANY STORY:\n{extracted['about_content']}")
        if extracted.get("target_audience"):
            parts.append(f"TARGET AUDIENCE: {extracted['target_audience']}")
        if extracted.get("key_phrases"):
            parts.append(f"KEY PHRASES TO USE: {', '.join(extracted['key_phrases'])}")
        if extracted.get("team_info"):
            parts.append("TEAM MEMBERS:")
            for t in extracted["team_info"]:
                parts.append(f"  - {t}")
        if extracted.get("testimonials"):
            parts.append("REAL TESTIMONIALS (use these verbatim):")
            for t in extracted["testimonials"]:
                parts.append(f"  - {t}")
        if extracted.get("product_services"):
            parts.append("PRODUCTS/SERVICES:")
            for p in extracted["product_services"]:
                parts.append(f"  - {p}")
        if extracted.get("competitive_advantages"):
            parts.append(f"COMPETITIVE ADVANTAGES: {', '.join(extracted['competitive_advantages'])}")
        if extracted.get("statistics"):
            parts.append("REAL STATISTICS (use these instead of inventing):")
            for s in extracted["statistics"]:
                parts.append(f"  - {s}")
        if extracted.get("faq_content"):
            parts.append("FAQ FROM BRAND DOCS:")
            for faq in extracted["faq_content"]:
                if isinstance(faq, dict):
                    parts.append(f"  Q: {faq.get('q', '')}")
                    parts.append(f"  A: {faq.get('a', '')}")
        if extracted.get("pricing_info"):
            parts.append(f"PRICING INFO: {extracted['pricing_info']}")
        if extracted.get("contact_info"):
            parts.append(f"CONTACT: {extracted['contact_info']}")
        if extracted.get("additional_content"):
            parts.append(f"ADDITIONAL CONTEXT:\n{extracted['additional_content']}")

    if image_classifications:
        parts.append("\nUPLOADED IMAGES:")
        for img in image_classifications:
            label = CLASSIFICATION_LABELS.get(img.get("classification", "other"), "Other")
            parts.append(f"  - {img.get('filename', 'image')}: [{label}] {img.get('description', '')}")
            if img.get("suggested_sections"):
                parts.append(f"    Suggested for: {', '.join(img['suggested_sections'])}")

    parts.append("\n== END BRAND KIT ==\n")
    return "\n".join(parts)


def compute_file_hash(file_path: str) -> str:
    import hashlib
    h = hashlib.sha256()
    try:
        with open(file_path, 'rb') as f:
            for chunk in iter(lambda: f.read(8192), b''):
                h.update(chunk)
        return h.hexdigest()
    except Exception as e:
        logger.error(f"Hash computation failed for {file_path}: {e}")
        return ""


def resolve_assets_for_sections(assets) -> dict:
    section_assets = {}
    for asset in assets:
        if isinstance(asset, dict):
            cls = asset.get("classification", "other")
            asset_type = asset.get("asset_type", "")
            sections = asset.get("used_in_sections") or CLASSIFICATION_TO_SECTIONS.get(cls, [])
            asset_data = {
                "id": asset.get("id"),
                "filename": asset.get("filename", ""),
                "file_path": asset.get("file_path", ""),
                "classification": cls,
                "classification_label": CLASSIFICATION_LABELS.get(cls, "Other"),
                "description": asset.get("ai_description") or asset.get("description", ""),
                "tags": asset.get("tags", []),
                "asset_type": asset_type,
            }
        elif hasattr(asset, "classification"):
            cls = asset.classification or "other"
            asset_type = asset.asset_type or ""
            sections = asset.used_in_sections or CLASSIFICATION_TO_SECTIONS.get(cls, [])
            asset_data = {
                "id": asset.id,
                "filename": asset.filename,
                "file_path": asset.file_path,
                "classification": cls,
                "classification_label": CLASSIFICATION_LABELS.get(cls, "Other"),
                "description": asset.ai_description or "",
                "tags": asset.tags or [],
                "asset_type": asset_type,
            }
        else:
            continue

        if asset_type == "document":
            continue

        for section in sections:
            if section not in section_assets:
                section_assets[section] = []
            section_assets[section].append(asset_data)

    return section_assets


CLASSIFICATION_TO_SECTIONS = {
    "hero_banner": ["hero", "about"],
    "logo": ["hero", "nav", "footer"],
    "team_photo": ["team", "about", "testimonials"],
    "product_shot": ["features", "pricing", "gallery", "comparison"],
    "lifestyle": ["hero", "about", "gallery"],
    "background_texture": ["hero", "cta", "footer"],
    "icon_graphic": ["features", "how_it_works", "benefits"],
    "testimonial_headshot": ["testimonials", "social_proof"],
    "gallery": ["gallery", "portfolio", "case_studies"],
    "infographic": ["stats", "features", "how_it_works", "data"],
    "section_separator": ["problem", "solution", "features", "how_it_works", "pricing", "testimonials", "faq", "cta", "about"],
    "other": [],
}

GAP_CHECKLIST = {
    "required": [
        {"key": "mission_statement", "label": "Mission Statement", "source": "document", "tip": "Upload a document containing your mission or purpose statement."},
        {"key": "about_content", "label": "About / Company Story", "source": "document", "tip": "Upload an about page, company bio, or founding story."},
        {"key": "product_services", "label": "Products or Services", "source": "document", "tip": "Upload a document listing your products, services, or offerings."},
    ],
    "recommended": [
        {"key": "logo", "label": "Logo Image", "source": "image", "classification": "logo", "tip": "Upload your logo (PNG or SVG preferred)."},
        {"key": "hero_image", "label": "Hero / Banner Image", "source": "image", "classification": "hero_banner", "tip": "Upload a high-quality hero image (1920x1080+ recommended)."},
        {"key": "testimonials", "label": "Testimonials", "source": "document", "tip": "Upload real customer testimonials or reviews."},
        {"key": "team_info", "label": "Team Information", "source": "document", "tip": "Upload team bios, headshots, or an org chart."},
        {"key": "core_values", "label": "Core Values", "source": "document", "tip": "Upload a document stating your brand values or principles."},
        {"key": "brand_voice", "label": "Brand Voice / Tone Guide", "source": "document", "tip": "Upload a style guide or tone-of-voice document."},
        {"key": "target_audience", "label": "Target Audience Profile", "source": "document", "tip": "Upload an ideal customer profile or audience persona."},
        {"key": "pricing_info", "label": "Pricing Details", "source": "document", "tip": "Upload pricing tiers, rate cards, or pricing strategy."},
        {"key": "statistics", "label": "Real Statistics / Metrics", "source": "document", "tip": "Upload real performance numbers, growth stats, or case study metrics."},
        {"key": "faq_content", "label": "FAQ Content", "source": "document", "tip": "Upload frequently asked questions and answers."},
        {"key": "competitive_advantages", "label": "Competitive Advantages", "source": "document", "tip": "Upload a document describing what makes you different."},
    ],
    "nice_to_have": [
        {"key": "team_photos", "label": "Team Photos", "source": "image", "classification": "team_photo", "tip": "Upload individual headshots or team group photos."},
        {"key": "product_images", "label": "Product Images", "source": "image", "classification": "product_shot", "tip": "Upload photos of your products or service in action."},
        {"key": "lifestyle_images", "label": "Lifestyle / Atmosphere Images", "source": "image", "classification": "lifestyle", "tip": "Upload lifestyle photos that capture your brand's feel."},
        {"key": "contact_info", "label": "Contact Information", "source": "document", "tip": "Upload contact details, office address, or support channels."},
    ],
}


def build_brandkit_summary(extracted: dict, image_classifications: list, domain: str) -> dict:
    from app.services.llm import call_llm

    content_pieces = []
    if extracted:
        for key, val in extracted.items():
            if val and key != "error":
                if isinstance(val, list):
                    content_pieces.append(f"{key}: {', '.join(str(v) for v in val[:5])}")
                elif isinstance(val, str) and len(val) > 10:
                    content_pieces.append(f"{key}: {val[:200]}")

    image_summary = []
    if image_classifications:
        for img in image_classifications:
            cls = img.get("classification", "other")
            label = CLASSIFICATION_LABELS.get(cls, "Other")
            image_summary.append(f"{label}: {img.get('description', 'no description')[:100]}")

    if not content_pieces and not image_summary:
        return {
            "tone": "Not enough content to determine",
            "keywords": [],
            "visual_motifs": [],
            "brand_personality": "Upload more brand materials for AI analysis",
            "content_strength": "minimal",
            "asset_count": {"documents": 0, "images": 0},
        }

    doc_section = chr(10).join(content_pieces[:20]) if content_pieces else "(No document content — analyze from images only)"
    img_section = chr(10).join(image_summary[:15]) if image_summary else "(No images uploaded)"

    prompt = f"""Analyze this brand kit content for the domain "{domain}" and produce a concise intelligence summary.

DOCUMENT CONTENT:
{doc_section}

UPLOADED IMAGES:
{img_section}

Return JSON with exactly these fields:
{{
  "tone": "2-3 word tone description (e.g., 'Professional and warm', 'Bold and playful')",
  "keywords": ["keyword1", "keyword2", "keyword3", "keyword4", "keyword5"],
  "visual_motifs": ["motif1", "motif2", "motif3"],
  "brand_personality": "One paragraph summary of the brand's identity, voice, and positioning based on all uploaded materials",
  "content_strength": "minimal|moderate|strong|comprehensive"
}}"""

    system = "You are a brand strategist. Analyze brand materials and produce concise intelligence summaries. Always respond with valid JSON."

    try:
        result = call_llm(prompt, system, max_tokens=8192)
        if isinstance(result, str):
            try:
                result = json.loads(result)
            except json.JSONDecodeError:
                logger.error(f"Brand kit summary returned invalid JSON: {result[:200]}")
                return {"tone": "Analysis failed", "keywords": [], "visual_motifs": [], "brand_personality": "AI returned invalid response", "content_strength": "minimal", "asset_count": {"documents": len(content_pieces), "images": len(image_summary)}}
        if isinstance(result, dict):
            doc_count = len(content_pieces)
            img_count = len(image_summary)
            result["asset_count"] = {"documents": doc_count, "images": img_count}
            return result
        return {"tone": "Analysis failed", "keywords": [], "visual_motifs": [], "brand_personality": "Could not analyze", "content_strength": "minimal", "asset_count": {"documents": 0, "images": 0}}
    except Exception as e:
        logger.error(f"Brand kit summary generation failed for {domain}: {e}")
        return {"tone": "Analysis error", "keywords": [], "visual_motifs": [], "brand_personality": f"Error: {e}", "content_strength": "minimal", "asset_count": {"documents": 0, "images": 0}}


def compute_gap_analysis(extracted: dict, assets: list) -> dict:
    image_classifications_found = set()
    if assets:
        for asset in assets:
            cls = None
            if isinstance(asset, dict):
                cls = asset.get("classification")
            elif hasattr(asset, "classification"):
                cls = asset.classification
            if cls:
                image_classifications_found.add(cls)

    doc_fields = extracted if extracted else {}

    missing_required = []
    present_required = []
    for item in GAP_CHECKLIST["required"]:
        if item["source"] == "document":
            val = doc_fields.get(item["key"])
            has_it = bool(val and ((isinstance(val, str) and len(val) > 5) or (isinstance(val, list) and len(val) > 0)))
        else:
            has_it = item.get("classification", "") in image_classifications_found
        if has_it:
            present_required.append({"key": item["key"], "label": item["label"]})
        else:
            missing_required.append({"key": item["key"], "label": item["label"], "tip": item["tip"], "source": item["source"]})

    missing_recommended = []
    present_recommended = []
    for item in GAP_CHECKLIST["recommended"]:
        if item["source"] == "document":
            val = doc_fields.get(item["key"])
            has_it = bool(val and ((isinstance(val, str) and len(val) > 5) or (isinstance(val, list) and len(val) > 0)))
        else:
            has_it = item.get("classification", "") in image_classifications_found
        if has_it:
            present_recommended.append({"key": item["key"], "label": item["label"]})
        else:
            missing_recommended.append({"key": item["key"], "label": item["label"], "tip": item["tip"], "source": item["source"]})

    missing_nice = []
    present_nice = []
    for item in GAP_CHECKLIST["nice_to_have"]:
        if item["source"] == "document":
            val = doc_fields.get(item["key"])
            has_it = bool(val and ((isinstance(val, str) and len(val) > 5) or (isinstance(val, list) and len(val) > 0)))
        else:
            has_it = item.get("classification", "") in image_classifications_found
        if has_it:
            present_nice.append({"key": item["key"], "label": item["label"]})
        else:
            missing_nice.append({"key": item["key"], "label": item["label"], "tip": item["tip"], "source": item["source"]})

    total_items = len(GAP_CHECKLIST["required"]) + len(GAP_CHECKLIST["recommended"]) + len(GAP_CHECKLIST["nice_to_have"])
    present_count = len(present_required) + len(present_recommended) + len(present_nice)
    completeness_pct = round((present_count / total_items) * 100) if total_items > 0 else 0

    if completeness_pct >= 80:
        grade = "A"
        grade_label = "Excellent"
    elif completeness_pct >= 60:
        grade = "B"
        grade_label = "Good"
    elif completeness_pct >= 40:
        grade = "C"
        grade_label = "Fair"
    elif completeness_pct >= 20:
        grade = "D"
        grade_label = "Needs Work"
    else:
        grade = "F"
        grade_label = "Minimal"

    return {
        "completeness_pct": completeness_pct,
        "grade": grade,
        "grade_label": grade_label,
        "missing_required": missing_required,
        "present_required": present_required,
        "missing_recommended": missing_recommended,
        "present_recommended": present_recommended,
        "missing_nice_to_have": missing_nice,
        "present_nice_to_have": present_nice,
        "total_items": total_items,
        "present_count": present_count,
    }


def compute_image_suggestions(assets: list) -> list:
    suggestions = []
    if not assets:
        return suggestions

    for asset in assets:
        if isinstance(asset, dict):
            cls = asset.get("classification", "other")
            asset_id = asset.get("id")
            filename = asset.get("filename", "")
            desc = asset.get("description", "")
            asset_type = asset.get("asset_type", "")
        elif hasattr(asset, "classification"):
            cls = asset.classification or "other"
            asset_id = asset.id
            filename = asset.filename
            desc = asset.ai_description or ""
            asset_type = asset.asset_type
        else:
            continue

        if asset_type == "document":
            continue

        matched_sections = CLASSIFICATION_TO_SECTIONS.get(cls, [])
        if matched_sections:
            suggestions.append({
                "asset_id": asset_id,
                "filename": filename,
                "classification": cls,
                "classification_label": CLASSIFICATION_LABELS.get(cls, "Other"),
                "suggested_sections": matched_sections,
                "description": desc[:150] if desc else "",
                "confidence": "high" if cls in ("hero_banner", "logo", "testimonial_headshot") else "medium",
            })

    return suggestions


def port_graphics_to_brandkit(domain: str, db_session) -> dict:
    from app.models import Package, BrandKit, BrandKitAsset, Domain
    import datetime

    dom = db_session.query(Domain).filter(Domain.domain == domain).first()
    if not dom:
        return {"status": "error", "message": "Domain not found"}
    pkg = db_session.query(Package).filter(Package.domain_id == dom.id).order_by(Package.id.desc()).first()
    if not pkg:
        return {"status": "error", "message": "No package found for domain"}

    graphics_pack = pkg.graphics_pack or {}
    from app.services.graphics import flatten_pack_assets
    flat_assets = flatten_pack_assets(graphics_pack)
    if not flat_assets:
        return {"status": "error", "message": "No graphics pack found — generate one first"}

    kit = db_session.query(BrandKit).filter(BrandKit.domain == domain, BrandKit.status == "ready").first()
    if not kit:
        kit = BrandKit(
            domain=domain,
            status="ready",
            extracted={},
            image_classifications={},
            created_at=datetime.datetime.utcnow(),
            updated_at=datetime.datetime.utcnow(),
        )
        db_session.add(kit)
        db_session.flush()

    existing_hashes = set()
    existing_filenames = set()
    existing_assets = db_session.query(BrandKitAsset).filter(BrandKitAsset.brand_kit_id == kit.id).all()
    for ea in existing_assets:
        if ea.file_hash:
            existing_hashes.add(ea.file_hash)
        if ea.filename:
            existing_filenames.add(ea.filename)

    imported = []
    skipped = []
    for asset in flat_assets:
        url = asset.get("url", "")
        content_hash = asset.get("content_hash", "")
        asset_filename = asset.get("filename", os.path.basename(url) if url else "")
        if content_hash and content_hash in existing_hashes:
            skipped.append({"asset_id": asset.get("asset_id"), "reason": "duplicate_hash"})
            continue
        if asset_filename and asset_filename in existing_filenames:
            skipped.append({"asset_id": asset.get("asset_id"), "reason": "duplicate_filename"})
            continue

        file_path = url.lstrip("/") if url else ""
        if not file_path or not os.path.exists(file_path):
            skipped.append({"asset_id": asset.get("asset_id"), "reason": "file_missing"})
            continue

        file_size = os.path.getsize(file_path) if os.path.exists(file_path) else 0
        classification = asset.get("classification", "other")
        display_name = asset.get("display_name", asset.get("filename", ""))
        section_type = asset.get("section")
        suggested_sections = CLASSIFICATION_TO_SECTIONS.get(classification, [])
        if section_type:
            suggested_sections = [section_type] + [s for s in suggested_sections if s != section_type]

        tags = ["graphics-pack", f"asset-id:{asset.get('asset_id', '')}"]
        asset_type_tag = asset.get("type", "")
        if asset_type_tag:
            tags.append(f"gp-type:{asset_type_tag}")
        style = asset.get("style")
        if style:
            tags.append(f"style:{style}")

        bka = BrandKitAsset(
            brand_kit_id=kit.id,
            asset_type="image",
            filename=asset.get("filename", os.path.basename(file_path)),
            file_path=file_path,
            file_size=file_size,
            file_hash=content_hash or None,
            classification=classification,
            tags=tags,
            ai_description=display_name,
            sort_order=0,
            suggested_sections=suggested_sections,
            used_in_sections=suggested_sections[:3] if suggested_sections else None,
            classified_at=datetime.datetime.utcnow(),
            created_at=datetime.datetime.utcnow(),
        )
        db_session.add(bka)
        if content_hash:
            existing_hashes.add(content_hash)
        if asset_filename:
            existing_filenames.add(asset_filename)
        imported.append({
            "asset_id": asset.get("asset_id"),
            "filename": bka.filename,
            "classification": classification,
            "display_name": display_name,
        })

    db_session.commit()

    return {
        "status": "ok",
        "brand_kit_id": kit.id,
        "imported": len(imported),
        "skipped": len(skipped),
        "details": {"imported": imported, "skipped": skipped},
    }


def port_single_asset_to_brandkit(domain: str, asset_url: str, asset_filename: str, classification: str, db_session) -> dict:
    from app.models import BrandKit, BrandKitAsset
    import datetime

    ALLOWED_PREFIXES = ("/static/images/", "/static/graphics/", "/static/uploads/")
    if not any(asset_url.startswith(p) for p in ALLOWED_PREFIXES):
        return {"status": "error", "message": "Invalid asset path — must be a static asset"}

    file_path = asset_url.lstrip("/") if asset_url else ""
    real_path = os.path.realpath(file_path)
    allowed_dirs = [os.path.realpath(p.strip("/")) for p in ALLOWED_PREFIXES]
    if not any(real_path.startswith(d) for d in allowed_dirs):
        return {"status": "error", "message": "Invalid asset path — path traversal blocked"}
    if not os.path.exists(file_path):
        return {"status": "error", "message": "Asset file not found on disk"}

    content_hash = None
    try:
        import hashlib
        with open(file_path, "rb") as f:
            content_hash = hashlib.sha256(f.read()).hexdigest()
    except Exception:
        pass

    kit = db_session.query(BrandKit).filter(BrandKit.domain == domain, BrandKit.status == "ready").first()
    if not kit:
        kit = BrandKit(
            domain=domain,
            status="ready",
            extracted={},
            image_classifications={},
            created_at=datetime.datetime.utcnow(),
            updated_at=datetime.datetime.utcnow(),
        )
        db_session.add(kit)
        db_session.flush()

    if content_hash:
        existing = db_session.query(BrandKitAsset).filter(
            BrandKitAsset.brand_kit_id == kit.id,
            BrandKitAsset.file_hash == content_hash
        ).first()
        if existing:
            return {"status": "ok", "imported": 0, "skipped": 1, "message": "Already in brand kit (duplicate hash)"}

    if asset_filename:
        existing = db_session.query(BrandKitAsset).filter(
            BrandKitAsset.brand_kit_id == kit.id,
            BrandKitAsset.filename == asset_filename
        ).first()
        if existing:
            return {"status": "ok", "imported": 0, "skipped": 1, "message": "Already in brand kit (duplicate filename)"}

    file_size = os.path.getsize(file_path)
    suggested_sections = CLASSIFICATION_TO_SECTIONS.get(classification, [])

    bka = BrandKitAsset(
        brand_kit_id=kit.id,
        asset_type="image",
        filename=asset_filename or os.path.basename(file_path),
        file_path=file_path,
        file_size=file_size,
        file_hash=content_hash,
        classification=classification,
        tags=["graphics-pack", "individual-port"],
        ai_description=asset_filename,
        sort_order=0,
        suggested_sections=suggested_sections,
        used_in_sections=suggested_sections[:3] if suggested_sections else None,
        classified_at=datetime.datetime.utcnow(),
        created_at=datetime.datetime.utcnow(),
    )
    db_session.add(bka)
    db_session.commit()

    return {"status": "ok", "imported": 1, "skipped": 0, "asset_id": bka.id, "filename": bka.filename}
