"""
Domain Listings API - Pounce Marketplace

This implements the "Micro-Marktplatz" from analysis_3.md:
- Create professional "For Sale" landing pages
- DNS verification for ownership
- Contact form for buyers
- Analytics

Endpoints:
- GET /listings - Public: Browse active listings
- GET /listings/{slug} - Public: View listing details
- POST /listings/{slug}/inquire - Public: Contact seller
- POST /listings - Auth: Create new listing
- GET /listings/my - Auth: Get user's listings
- PUT /listings/{id} - Auth: Update listing
- DELETE /listings/{id} - Auth: Delete listing
- POST /listings/{id}/verify-dns - Auth: Start DNS verification
- GET /listings/{id}/verify-dns/check - Auth: Check verification status
"""
import logging
import secrets
import re
from datetime import datetime, timedelta
from typing import Optional, List
from fastapi import APIRouter, Depends, Query, HTTPException, Request
from pydantic import BaseModel, Field, EmailStr
from sqlalchemy import select, func, and_
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.database import get_db
from app.api.deps import get_current_user, get_current_user_optional
from app.models.user import User
from app.models.listing import (
    DomainListing,
    ListingInquiry,
    ListingInquiryEvent,
    ListingInquiryMessage,
    ListingView,
    ListingStatus,
    VerificationStatus,
)
from app.services.valuation import valuation_service
from app.services.telemetry import track_event


def _calculate_pounce_score(domain: str, is_pounce: bool = True) -> int:
    """
    Calculate Pounce Score for a domain.
    Uses the same algorithm as Market Feed (_calculate_pounce_score_v2 in auctions.py).
    """
    # Parse domain
    parts = domain.lower().rsplit(".", 1)
    if len(parts) != 2:
        return 50
    
    name, tld = parts
    score = 50  # Baseline
    
    # A) LENGTH BONUS (exponential for short domains)
    length_scores = {1: 50, 2: 45, 3: 40, 4: 30, 5: 20, 6: 15, 7: 10}
    score += length_scores.get(len(name), max(0, 15 - len(name)))
    
    # B) TLD PREMIUM
    tld_scores = {
        'com': 20, 'ai': 25, 'io': 18, 'co': 12, 
        'ch': 15, 'de': 10, 'net': 8, 'org': 8,
        'app': 10, 'dev': 10, 'xyz': 5
    }
    score += tld_scores.get(tld.lower(), 0)
    
    # C) POUNCE DIRECT BONUS (listings are always Pounce Direct)
    if is_pounce:
        score += 10
    
    # D) PENALTIES
    if '-' in name:
        score -= 25
    if any(c.isdigit() for c in name) and len(name) > 3:
        score -= 20
    if len(name) > 15:
        score -= 15
    
    # Clamp to 0-100
    return max(0, min(100, score))

logger = logging.getLogger(__name__)
router = APIRouter()


# ============== Schemas ==============

class ListingCreate(BaseModel):
    """Create a new domain listing."""
    domain: str = Field(..., min_length=3, max_length=255)
    title: Optional[str] = Field(None, max_length=200)
    description: Optional[str] = None
    asking_price: Optional[float] = Field(None, ge=0)
    min_offer: Optional[float] = Field(None, ge=0)
    currency: str = Field("USD", max_length=3)
    price_type: str = Field("negotiable")  # fixed, negotiable, make_offer
    show_valuation: bool = True
    allow_offers: bool = True


class ListingUpdate(BaseModel):
    """Update a listing."""
    title: Optional[str] = Field(None, max_length=200)
    description: Optional[str] = None
    asking_price: Optional[float] = Field(None, ge=0)
    min_offer: Optional[float] = Field(None, ge=0)
    price_type: Optional[str] = None
    show_valuation: Optional[bool] = None
    allow_offers: Optional[bool] = None
    status: Optional[str] = None
    sold_reason: Optional[str] = Field(None, max_length=200)
    sold_price: Optional[float] = Field(None, ge=0)
    sold_currency: Optional[str] = Field(None, max_length=3)


class ListingResponse(BaseModel):
    """Listing response."""
    id: int
    domain: str
    slug: str
    title: Optional[str]
    description: Optional[str]
    asking_price: Optional[float]
    min_offer: Optional[float]
    currency: str
    price_type: str
    pounce_score: Optional[int]
    estimated_value: Optional[float]
    verification_status: str
    is_verified: bool
    status: str
    show_valuation: bool
    allow_offers: bool
    view_count: int
    inquiry_count: int
    public_url: str
    created_at: datetime
    published_at: Optional[datetime]
    sold_at: Optional[datetime] = None
    sold_reason: Optional[str] = None
    sold_price: Optional[float] = None
    sold_currency: Optional[str] = None
    
    # Seller info (minimal for privacy)
    seller_verified: bool = False
    seller_member_since: Optional[datetime] = None
    
    class Config:
        from_attributes = True


class ListingPublicResponse(BaseModel):
    """Public listing response (limited info)."""
    domain: str
    slug: str
    title: Optional[str]
    description: Optional[str]
    asking_price: Optional[float]
    currency: str
    price_type: str
    pounce_score: Optional[int]
    estimated_value: Optional[float]
    is_verified: bool
    allow_offers: bool
    public_url: str
    
    # Seller trust indicators
    seller_verified: bool
    seller_member_since: Optional[datetime]
    seller_invite_code: Optional[str] = None
    
    class Config:
        from_attributes = True


class InquiryCreate(BaseModel):
    """Create an inquiry for a listing."""
    name: str = Field(..., min_length=2, max_length=100)
    email: EmailStr
    phone: Optional[str] = Field(None, max_length=50)
    company: Optional[str] = Field(None, max_length=200)
    message: str = Field(..., min_length=10, max_length=2000)
    offer_amount: Optional[float] = Field(None, ge=0)


class InquiryResponse(BaseModel):
    """Inquiry response for listing owner."""
    id: int
    name: str
    email: str
    phone: Optional[str]
    company: Optional[str]
    message: str
    offer_amount: Optional[float]
    status: str
    created_at: datetime
    read_at: Optional[datetime]
    replied_at: Optional[datetime] = None
    closed_at: Optional[datetime] = None
    closed_reason: Optional[str] = None
    buyer_user_id: Optional[int] = None
    
    class Config:
        from_attributes = True


class InquiryUpdate(BaseModel):
    """Update inquiry status for listing owner."""
    status: str = Field(..., min_length=1, max_length=20)  # new, read, replied, spam
    reason: Optional[str] = Field(None, max_length=200)


class InquiryMessageCreate(BaseModel):
    body: str = Field(..., min_length=1, max_length=4000)


class InquiryMessageResponse(BaseModel):
    id: int
    inquiry_id: int
    listing_id: int
    sender_user_id: int
    body: str
    created_at: datetime

    class Config:
        from_attributes = True


class VerificationResponse(BaseModel):
    """DNS verification response."""
    verification_code: str
    dns_record_type: str = "TXT"
    dns_record_name: str
    dns_record_value: str
    instructions: str
    status: str


# ============== Helper Functions ==============

def _generate_slug(domain: str) -> str:
    """Generate URL-friendly slug from domain."""
    # Remove TLD for cleaner slug
    slug = domain.lower().replace('.', '-')
    # Remove any non-alphanumeric chars except hyphens
    slug = re.sub(r'[^a-z0-9-]', '', slug)
    return slug


def _generate_verification_code() -> str:
    """Generate a unique verification code."""
    return f"pounce-verify-{secrets.token_hex(16)}"


# Security: Block phishing keywords (from analysis_3.md - Säule 3)
BLOCKED_KEYWORDS = [
    'login', 'bank', 'verify', 'paypal', 'password', 'account', 
    'credit', 'social security', 'ssn', 'wire', 'transfer'
]


def _check_content_safety(text: str) -> bool:
    """Check if content contains phishing keywords."""
    text_lower = text.lower()
    return not any(keyword in text_lower for keyword in BLOCKED_KEYWORDS)


# ============== Public Endpoints ==============

@router.get("", response_model=List[ListingPublicResponse])
async def browse_listings(
    keyword: Optional[str] = Query(None),
    min_price: Optional[float] = Query(None, ge=0),
    max_price: Optional[float] = Query(None, ge=0),
    verified_only: bool = Query(False),
    clean_only: bool = Query(True, description="Hide low-quality/spam listings"),
    sort_by: str = Query("newest", enum=["newest", "price_asc", "price_desc", "popular"]),
    limit: int = Query(20, le=50),
    offset: int = Query(0, ge=0),
    db: AsyncSession = Depends(get_db),
):
    """Browse active domain listings (public)."""
    query = select(DomainListing).options(selectinload(DomainListing.user)).where(
        DomainListing.status == ListingStatus.ACTIVE.value
    )
    
    if keyword:
        query = query.where(DomainListing.domain.ilike(f"%{keyword}%"))
    
    if min_price is not None:
        query = query.where(DomainListing.asking_price >= min_price)
    
    if max_price is not None:
        query = query.where(DomainListing.asking_price <= max_price)
    
    if verified_only:
        query = query.where(
            DomainListing.verification_status == VerificationStatus.VERIFIED.value
        )
    
    # Sorting
    if sort_by == "price_asc":
        query = query.order_by(DomainListing.asking_price.asc().nullslast())
    elif sort_by == "price_desc":
        query = query.order_by(DomainListing.asking_price.desc().nullsfirst())
    elif sort_by == "popular":
        query = query.order_by(DomainListing.view_count.desc())
    else:  # newest
        query = query.order_by(DomainListing.published_at.desc())
    
    query = query.offset(offset).limit(limit)
    
    result = await db.execute(query)
    listings = list(result.scalars().all())
    
    responses = []
    for listing in listings:
        # Calculate pounce_score dynamically if not stored
        pounce_score = listing.pounce_score
        if pounce_score is None:
            pounce_score = _calculate_pounce_score(listing.domain)
            # Save it for future requests
            listing.pounce_score = pounce_score

        # Public cleanliness rule: don't surface low-quality inventory by default.
        # (Still accessible in Terminal for authenticated power users.)
        if clean_only and (pounce_score or 0) < 50:
            continue
        
        responses.append(ListingPublicResponse(
            domain=listing.domain,
            slug=listing.slug,
            title=listing.title,
            description=listing.description,
            asking_price=listing.asking_price,
            currency=listing.currency,
            price_type=listing.price_type,
            pounce_score=pounce_score,  # Always return the score
            estimated_value=listing.estimated_value if listing.show_valuation else None,
            is_verified=listing.is_verified,
            allow_offers=listing.allow_offers,
            public_url=listing.public_url,
            seller_verified=listing.is_verified,
            seller_member_since=listing.user.created_at if listing.user else None,
            seller_invite_code=getattr(listing.user, "invite_code", None) if listing.user else None,
        ))
    
    await db.commit()  # Save any updated pounce_scores
    return responses


# ============== Authenticated Endpoints (before dynamic routes!) ==============

@router.get("/my", response_model=List[ListingResponse])
async def get_my_listings(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get current user's listings."""
    result = await db.execute(
        select(DomainListing)
        .where(DomainListing.user_id == current_user.id)
        .order_by(DomainListing.created_at.desc())
    )
    listings = list(result.scalars().all())
    
    return [
        ListingResponse(
            id=listing.id,
            domain=listing.domain,
            slug=listing.slug,
            title=listing.title,
            description=listing.description,
            asking_price=listing.asking_price,
            min_offer=listing.min_offer,
            currency=listing.currency,
            price_type=listing.price_type,
            pounce_score=listing.pounce_score,
            estimated_value=listing.estimated_value,
            verification_status=listing.verification_status,
            is_verified=listing.is_verified,
            status=listing.status,
            show_valuation=listing.show_valuation,
            allow_offers=listing.allow_offers,
            view_count=listing.view_count,
            inquiry_count=listing.inquiry_count,
            public_url=listing.public_url,
            created_at=listing.created_at,
            published_at=listing.published_at,
            sold_at=getattr(listing, "sold_at", None),
            sold_reason=getattr(listing, "sold_reason", None),
            sold_price=getattr(listing, "sold_price", None),
            sold_currency=getattr(listing, "sold_currency", None),
            seller_verified=current_user.is_verified,
            seller_member_since=current_user.created_at,
        )
        for listing in listings
    ]


# ============== Public Dynamic Routes ==============

@router.get("/{slug}", response_model=ListingPublicResponse)
async def get_listing_by_slug(
    slug: str,
    request: Request,
    db: AsyncSession = Depends(get_db),
    current_user: Optional[User] = Depends(get_current_user_optional),
):
    """Get listing details by slug (public)."""
    result = await db.execute(
        select(DomainListing)
        .options(selectinload(DomainListing.user))
        .where(
            and_(
                DomainListing.slug == slug,
                DomainListing.status == ListingStatus.ACTIVE.value,
            )
        )
    )
    listing = result.scalar_one_or_none()
    
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")
    
    # Record view
    view = ListingView(
        listing_id=listing.id,
        ip_address=request.client.host if request.client else None,
        user_agent=request.headers.get("user-agent", "")[:500],
        referrer=request.headers.get("referer", "")[:500],
        user_id=current_user.id if current_user else None,
    )
    db.add(view)
    
    # Increment view count
    listing.view_count += 1

    await track_event(
        db,
        event_name="listing_view",
        request=request,
        user_id=current_user.id if current_user else None,
        is_authenticated=bool(current_user),
        source="public",
        domain=listing.domain,
        listing_id=listing.id,
        metadata={"slug": listing.slug},
    )
    
    # Calculate pounce_score dynamically if not stored (same as Market Feed)
    pounce_score = listing.pounce_score
    if pounce_score is None:
        pounce_score = _calculate_pounce_score(listing.domain)
        # Save it for future requests
        listing.pounce_score = pounce_score
    
    await db.commit()
    
    return ListingPublicResponse(
        domain=listing.domain,
        slug=listing.slug,
        title=listing.title,
        description=listing.description,
        asking_price=listing.asking_price,
        currency=listing.currency,
        price_type=listing.price_type,
        pounce_score=pounce_score,  # Always return the score
        estimated_value=listing.estimated_value if listing.show_valuation else None,
        is_verified=listing.is_verified,
        allow_offers=listing.allow_offers,
        public_url=listing.public_url,
        seller_verified=listing.is_verified,
        seller_member_since=listing.user.created_at if listing.user else None,
        seller_invite_code=getattr(listing.user, "invite_code", None) if listing.user else None,
    )


@router.post("/{slug}/inquire")
async def submit_inquiry(
    slug: str,
    inquiry: InquiryCreate,
    request: Request,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Submit an inquiry for a listing (requires authentication)."""
    # Find listing
    result = await db.execute(
        select(DomainListing).where(
            and_(
                DomainListing.slug == slug,
                DomainListing.status == ListingStatus.ACTIVE.value,
            )
        )
    )
    listing = result.scalar_one_or_none()
    
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")

    # Require that inquiries are sent from the authenticated account email.
    # This prevents anonymous spam and makes the buyer identity consistent.
    if inquiry.email.lower() != (current_user.email or "").lower():
        raise HTTPException(
            status_code=400,
            detail="Inquiry email must match your account email.",
        )
    
    # Security: Check for phishing keywords
    if not _check_content_safety(inquiry.message):
        raise HTTPException(
            status_code=400, 
            detail="Message contains blocked content. Please revise."
        )
    
    # Rate limiting check (simple: max 3 inquiries per user per listing per day)
    today_start = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
    existing_count = await db.execute(
        select(func.count(ListingInquiry.id)).where(
            and_(
                ListingInquiry.listing_id == listing.id,
                ListingInquiry.buyer_user_id == current_user.id,
                ListingInquiry.created_at >= today_start,
            )
        )
    )
    if existing_count.scalar() >= 3:
        raise HTTPException(
            status_code=429, 
            detail="Too many inquiries. Please try again tomorrow."
        )
    
    # Create inquiry
    new_inquiry = ListingInquiry(
        listing_id=listing.id,
        buyer_user_id=current_user.id,
        name=inquiry.name,
        email=inquiry.email.lower(),
        phone=inquiry.phone,
        company=inquiry.company,
        message=inquiry.message,
        offer_amount=inquiry.offer_amount,
        ip_address=request.client.host if request.client else None,
        user_agent=request.headers.get("user-agent", "")[:500],
    )
    db.add(new_inquiry)
    await db.flush()

    await track_event(
        db,
        event_name="inquiry_created",
        request=request,
        user_id=current_user.id,
        is_authenticated=True,
        source="public",
        domain=listing.domain,
        listing_id=listing.id,
        inquiry_id=new_inquiry.id,
        metadata={
            "offer_amount": inquiry.offer_amount,
            "has_phone": bool(inquiry.phone),
            "has_company": bool(inquiry.company),
        },
    )

    # Seed thread with the initial message
    db.add(
        ListingInquiryMessage(
            inquiry_id=new_inquiry.id,
            listing_id=listing.id,
            sender_user_id=current_user.id,
            body=inquiry.message,
        )
    )
    
    # Increment inquiry count
    listing.inquiry_count += 1
    
    await db.commit()
    
    # Send email notification to seller
    try:
        from app.services.email_service import email_service
        from app.models.user import User
        
        # Get seller's email
        seller_result = await db.execute(
            select(User).where(User.id == listing.user_id)
        )
        seller = seller_result.scalar_one_or_none()
        
        if seller and seller.email and email_service.is_configured():
            await email_service.send_listing_inquiry(
                to_email=seller.email,
                domain=listing.domain,
                name=inquiry.name,
                email=inquiry.email,
                message=inquiry.message,
                company=inquiry.company,
                offer_amount=inquiry.offer_amount,
            )
            logger.info(f"📧 Inquiry notification sent to {seller.email} for {listing.domain}")
    except Exception as e:
        logger.error(f"Failed to send inquiry notification: {e}")
    
    return {
        "success": True,
        "message": "Your inquiry has been sent to the seller.",
    }


# ============== Listing Management (Authenticated) ==============

@router.post("", response_model=ListingResponse)
async def create_listing(
    data: ListingCreate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    Create a new domain listing.
    
    SECURITY: Domain must be in user's portfolio before listing for sale.
    DNS verification happens in the verification step (separate endpoint).
    """
    from app.models.portfolio import PortfolioDomain
    
    domain_lower = data.domain.lower()
    
    # SECURITY CHECK: Domain must be in user's portfolio
    portfolio_result = await db.execute(
        select(PortfolioDomain).where(
            PortfolioDomain.domain == domain_lower,
            PortfolioDomain.user_id == current_user.id,
        )
    )
    portfolio_domain = portfolio_result.scalar_one_or_none()
    
    if not portfolio_domain:
        raise HTTPException(
            status_code=403,
            detail="Domain must be in your portfolio before listing for sale. Add it to your portfolio first.",
        )
    
    # Check if domain is sold
    if portfolio_domain.is_sold:
        raise HTTPException(
            status_code=400,
            detail="Cannot list a sold domain for sale.",
        )
    
    # Check if domain is DNS verified in portfolio
    # If verified in portfolio, listing inherits verification
    is_portfolio_verified = getattr(portfolio_domain, 'is_dns_verified', False) or False
    
    # Check if domain is already listed
    existing = await db.execute(
        select(DomainListing).where(DomainListing.domain == domain_lower)
    )
    if existing.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="This domain is already listed")
    
    # Check user's listing limit based on subscription
    user_listings = await db.execute(
        select(func.count(DomainListing.id)).where(
            DomainListing.user_id == current_user.id
        )
    )
    listing_count = user_listings.scalar() or 0
    
    # Listing limits by tier - using TIER_CONFIG
    from app.models.subscription import Subscription, TIER_CONFIG, SubscriptionTier
    sub_result = await db.execute(
        select(Subscription).where(Subscription.user_id == current_user.id)
    )
    subscription = sub_result.scalar_one_or_none()
    tier = subscription.tier if subscription else SubscriptionTier.SCOUT
    tier_config = TIER_CONFIG.get(tier, TIER_CONFIG[SubscriptionTier.SCOUT])
    max_listings = tier_config.get("listing_limit", 0)
    # -1 means unlimited
    if max_listings == -1:
        max_listings = 999999
    
    if listing_count >= max_listings:
        raise HTTPException(
            status_code=403,
            detail=f"Listing limit reached ({max_listings}). Upgrade your plan for more."
        )
    
    # Generate slug
    slug = _generate_slug(domain_lower)
    
    # Check slug uniqueness
    slug_check = await db.execute(
        select(DomainListing).where(DomainListing.slug == slug)
    )
    if slug_check.scalar_one_or_none():
        slug = f"{slug}-{secrets.token_hex(4)}"
    
    # Get valuation
    try:
        valuation = await valuation_service.estimate_value(domain_lower, db, save_result=False)
        pounce_score = min(100, int(valuation.get("score", 50)))
        estimated_value = valuation.get("value", 0) # Fixed: was 'estimated_value', service returns 'value'
    except Exception:
        pounce_score = 50
        estimated_value = None
    
    # Create listing
    # If portfolio domain is already DNS verified, listing is auto-verified
    listing = DomainListing(
        user_id=current_user.id,
        domain=domain_lower,
        slug=slug,
        title=data.title,
        description=data.description,
        asking_price=data.asking_price,
        min_offer=data.min_offer,
        currency=data.currency.upper(),
        price_type=data.price_type,
        show_valuation=data.show_valuation,
        allow_offers=data.allow_offers,
        pounce_score=pounce_score,
        estimated_value=estimated_value,
        verification_code=portfolio_domain.verification_code if is_portfolio_verified else _generate_verification_code(),
        verification_status=VerificationStatus.VERIFIED.value if is_portfolio_verified else VerificationStatus.PENDING.value,
        verified_at=portfolio_domain.verified_at if is_portfolio_verified else None,
        status=ListingStatus.DRAFT.value,
    )
    
    db.add(listing)
    await db.commit()
    await db.refresh(listing)
    
    return ListingResponse(
        id=listing.id,
        domain=listing.domain,
        slug=listing.slug,
        title=listing.title,
        description=listing.description,
        asking_price=listing.asking_price,
        min_offer=listing.min_offer,
        currency=listing.currency,
        price_type=listing.price_type,
        pounce_score=listing.pounce_score,
        estimated_value=listing.estimated_value,
        verification_status=listing.verification_status,
        is_verified=listing.is_verified,
        status=listing.status,
        show_valuation=listing.show_valuation,
        allow_offers=listing.allow_offers,
        view_count=listing.view_count,
        inquiry_count=listing.inquiry_count,
        public_url=listing.public_url,
        created_at=listing.created_at,
        published_at=listing.published_at,
        seller_verified=current_user.is_verified,
        seller_member_since=current_user.created_at,
    )


@router.get("/{id}/inquiries", response_model=List[InquiryResponse])
async def get_listing_inquiries(
    id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Get inquiries for a listing."""
    # Verify ownership
    result = await db.execute(
        select(DomainListing).where(
            and_(
                DomainListing.id == id,
                DomainListing.user_id == current_user.id,
            )
        )
    )
    listing = result.scalar_one_or_none()
    
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")
    
    inquiries_result = await db.execute(
        select(ListingInquiry)
        .where(ListingInquiry.listing_id == id)
        .order_by(ListingInquiry.created_at.desc())
    )
    inquiries = list(inquiries_result.scalars().all())
    
    return [
        InquiryResponse(
            id=inq.id,
            name=inq.name,
            email=inq.email,
            phone=inq.phone,
            company=inq.company,
            message=inq.message,
            offer_amount=inq.offer_amount,
            status=inq.status,
            created_at=inq.created_at,
            read_at=inq.read_at,
            replied_at=getattr(inq, "replied_at", None),
            closed_at=getattr(inq, "closed_at", None),
            closed_reason=getattr(inq, "closed_reason", None),
            buyer_user_id=getattr(inq, "buyer_user_id", None),
        )
        for inq in inquiries
    ]


@router.patch("/{id}/inquiries/{inquiry_id}", response_model=InquiryResponse)
async def update_listing_inquiry(
    id: int,
    inquiry_id: int,
    data: InquiryUpdate,
    request: Request,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Update an inquiry status (listing owner only)."""
    allowed = {"new", "read", "replied", "closed", "spam"}
    status_clean = (data.status or "").strip().lower()
    if status_clean not in allowed:
        raise HTTPException(status_code=400, detail="Invalid status")

    # Verify listing ownership
    listing_result = await db.execute(
        select(DomainListing).where(
            and_(
                DomainListing.id == id,
                DomainListing.user_id == current_user.id,
            )
        )
    )
    listing = listing_result.scalar_one_or_none()
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")

    inquiry_result = await db.execute(
        select(ListingInquiry).where(
            and_(
                ListingInquiry.id == inquiry_id,
                ListingInquiry.listing_id == id,
            )
        )
    )
    inquiry = inquiry_result.scalar_one_or_none()
    if not inquiry:
        raise HTTPException(status_code=404, detail="Inquiry not found")

    now = datetime.utcnow()
    old_status = getattr(inquiry, "status", None)
    inquiry.status = status_clean
    if status_clean == "read" and inquiry.read_at is None:
        inquiry.read_at = now
    if status_clean == "replied":
        inquiry.replied_at = now
    if status_clean == "closed":
        inquiry.closed_at = now
        inquiry.closed_reason = (data.reason or "").strip() or None
    if status_clean == "spam":
        inquiry.closed_reason = (data.reason or "").strip() or inquiry.closed_reason

    # Audit trail
    event = ListingInquiryEvent(
        inquiry_id=inquiry.id,
        listing_id=listing.id,
        actor_user_id=current_user.id,
        old_status=old_status,
        new_status=status_clean,
        reason=(data.reason or "").strip() or None,
        ip_address=request.client.host if request.client else None,
        user_agent=request.headers.get("user-agent", "")[:500],
    )
    db.add(event)

    await track_event(
        db,
        event_name="inquiry_status_changed",
        request=request,
        user_id=current_user.id,
        is_authenticated=True,
        source="terminal",
        domain=listing.domain,
        listing_id=listing.id,
        inquiry_id=inquiry.id,
        metadata={"old_status": old_status, "new_status": status_clean, "reason": (data.reason or "").strip() or None},
    )

    await db.commit()
    await db.refresh(inquiry)

    return InquiryResponse(
        id=inquiry.id,
        name=inquiry.name,
        email=inquiry.email,
        phone=inquiry.phone,
        company=inquiry.company,
        message=inquiry.message,
        offer_amount=inquiry.offer_amount,
        status=inquiry.status,
        created_at=inquiry.created_at,
        read_at=inquiry.read_at,
        replied_at=getattr(inquiry, "replied_at", None),
        closed_at=getattr(inquiry, "closed_at", None),
        closed_reason=getattr(inquiry, "closed_reason", None),
        buyer_user_id=getattr(inquiry, "buyer_user_id", None),
    )


@router.get("/{id}/inquiries/{inquiry_id}/messages", response_model=List[InquiryMessageResponse])
async def get_inquiry_messages_for_seller(
    id: int,
    inquiry_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Seller: fetch thread messages for an inquiry."""
    listing_result = await db.execute(
        select(DomainListing).where(and_(DomainListing.id == id, DomainListing.user_id == current_user.id))
    )
    listing = listing_result.scalar_one_or_none()
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")

    inquiry_result = await db.execute(
        select(ListingInquiry).where(and_(ListingInquiry.id == inquiry_id, ListingInquiry.listing_id == id))
    )
    inquiry = inquiry_result.scalar_one_or_none()
    if not inquiry:
        raise HTTPException(status_code=404, detail="Inquiry not found")

    msgs = (
        await db.execute(
            select(ListingInquiryMessage)
            .where(and_(ListingInquiryMessage.inquiry_id == inquiry_id, ListingInquiryMessage.listing_id == id))
            .order_by(ListingInquiryMessage.created_at.asc())
        )
    ).scalars().all()
    return [InquiryMessageResponse.model_validate(m) for m in msgs]


@router.post("/{id}/inquiries/{inquiry_id}/messages", response_model=InquiryMessageResponse)
async def post_inquiry_message_as_seller(
    id: int,
    inquiry_id: int,
    payload: InquiryMessageCreate,
    request: Request,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Seller: post a message into an inquiry thread."""
    listing_result = await db.execute(
        select(DomainListing).where(and_(DomainListing.id == id, DomainListing.user_id == current_user.id))
    )
    listing = listing_result.scalar_one_or_none()
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")

    inquiry_result = await db.execute(
        select(ListingInquiry).where(and_(ListingInquiry.id == inquiry_id, ListingInquiry.listing_id == id))
    )
    inquiry = inquiry_result.scalar_one_or_none()
    if not inquiry:
        raise HTTPException(status_code=404, detail="Inquiry not found")

    if inquiry.status in ["closed", "spam"]:
        raise HTTPException(status_code=400, detail="Inquiry is closed")

    # Content safety (phishing keywords)
    if not _check_content_safety(payload.body):
        raise HTTPException(status_code=400, detail="Message contains blocked content. Please revise.")

    # Simple rate limit: max 30 messages per hour per inquiry
    hour_start = datetime.utcnow() - timedelta(hours=1)
    msg_count = (
        await db.execute(
            select(func.count(ListingInquiryMessage.id)).where(
                and_(
                    ListingInquiryMessage.inquiry_id == inquiry.id,
                    ListingInquiryMessage.sender_user_id == current_user.id,
                    ListingInquiryMessage.created_at >= hour_start,
                )
            )
        )
    ).scalar() or 0
    if msg_count >= 30:
        raise HTTPException(status_code=429, detail="Too many messages. Please slow down.")

    msg = ListingInquiryMessage(
        inquiry_id=inquiry.id,
        listing_id=listing.id,
        sender_user_id=current_user.id,
        body=payload.body,
    )
    db.add(msg)
    await db.flush()

    await track_event(
        db,
        event_name="message_sent",
        request=request,
        user_id=current_user.id,
        is_authenticated=True,
        source="terminal",
        domain=listing.domain,
        listing_id=listing.id,
        inquiry_id=inquiry.id,
        metadata={"role": "buyer"},
    )

    await track_event(
        db,
        event_name="message_sent",
        request=request,
        user_id=current_user.id,
        is_authenticated=True,
        source="terminal",
        domain=listing.domain,
        listing_id=listing.id,
        inquiry_id=inquiry.id,
        metadata={"role": "seller"},
    )

    # Email buyer (if configured)
    try:
        from app.services.email_service import email_service
        if inquiry.buyer_user_id:
            buyer = (
                await db.execute(select(User).where(User.id == inquiry.buyer_user_id))
            ).scalar_one_or_none()
        else:
            buyer = None
        if buyer and buyer.email and email_service.is_configured():
            thread_url = f"https://pounce.ch/terminal/inbox?inquiry={inquiry.id}"
            await email_service.send_listing_message(
                to_email=buyer.email,
                domain=listing.domain,
                sender_name=current_user.name or current_user.email,
                message=payload.body,
                thread_url=thread_url,
            )
    except Exception as e:
        logger.error(f"Failed to send listing message notification: {e}")

    await db.commit()
    await db.refresh(msg)
    return InquiryMessageResponse.model_validate(msg)


@router.get("/inquiries/my")
async def get_my_inquiries_as_buyer(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Buyer: list inquiries created from this account."""
    result = await db.execute(
        select(ListingInquiry, DomainListing)
        .join(DomainListing, DomainListing.id == ListingInquiry.listing_id)
        .where(ListingInquiry.buyer_user_id == current_user.id)
        .order_by(ListingInquiry.created_at.desc())
    )
    rows = result.all()
    return [
        {
            "id": inq.id,
            "listing_id": listing.id,
            "domain": listing.domain,
            "slug": listing.slug,
            "status": inq.status,
            "created_at": inq.created_at.isoformat(),
            "closed_at": inq.closed_at.isoformat() if getattr(inq, "closed_at", None) else None,
            "closed_reason": getattr(inq, "closed_reason", None),
        }
        for inq, listing in rows
    ]


@router.get("/inquiries/{inquiry_id}/messages", response_model=List[InquiryMessageResponse])
async def get_inquiry_messages_for_buyer(
    inquiry_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Buyer: fetch thread messages for one inquiry."""
    inquiry = (
        await db.execute(select(ListingInquiry).where(ListingInquiry.id == inquiry_id))
    ).scalar_one_or_none()
    if not inquiry or inquiry.buyer_user_id != current_user.id:
        raise HTTPException(status_code=404, detail="Inquiry not found")

    msgs = (
        await db.execute(
            select(ListingInquiryMessage)
            .where(ListingInquiryMessage.inquiry_id == inquiry_id)
            .order_by(ListingInquiryMessage.created_at.asc())
        )
    ).scalars().all()
    return [InquiryMessageResponse.model_validate(m) for m in msgs]


@router.post("/inquiries/{inquiry_id}/messages", response_model=InquiryMessageResponse)
async def post_inquiry_message_as_buyer(
    inquiry_id: int,
    payload: InquiryMessageCreate,
    request: Request,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Buyer: post a message into an inquiry thread."""
    inquiry = (
        await db.execute(select(ListingInquiry).where(ListingInquiry.id == inquiry_id))
    ).scalar_one_or_none()
    if not inquiry or inquiry.buyer_user_id != current_user.id:
        raise HTTPException(status_code=404, detail="Inquiry not found")

    if inquiry.status in ["closed", "spam"]:
        raise HTTPException(status_code=400, detail="Inquiry is closed")

    # Content safety (phishing keywords)
    if not _check_content_safety(payload.body):
        raise HTTPException(status_code=400, detail="Message contains blocked content. Please revise.")

    # Simple rate limit: max 20 messages per hour per inquiry
    hour_start = datetime.utcnow() - timedelta(hours=1)
    msg_count = (
        await db.execute(
            select(func.count(ListingInquiryMessage.id)).where(
                and_(
                    ListingInquiryMessage.inquiry_id == inquiry.id,
                    ListingInquiryMessage.sender_user_id == current_user.id,
                    ListingInquiryMessage.created_at >= hour_start,
                )
            )
        )
    ).scalar() or 0
    if msg_count >= 20:
        raise HTTPException(status_code=429, detail="Too many messages. Please slow down.")

    listing = (
        await db.execute(select(DomainListing).where(DomainListing.id == inquiry.listing_id))
    ).scalar_one_or_none()
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")

    msg = ListingInquiryMessage(
        inquiry_id=inquiry.id,
        listing_id=listing.id,
        sender_user_id=current_user.id,
        body=payload.body,
    )
    db.add(msg)
    await db.flush()

    # Email seller (if configured)
    try:
        from app.services.email_service import email_service
        seller = (
            await db.execute(select(User).where(User.id == listing.user_id))
        ).scalar_one_or_none()
        if seller and seller.email and email_service.is_configured():
            thread_url = f"https://pounce.ch/terminal/listing"
            await email_service.send_listing_message(
                to_email=seller.email,
                domain=listing.domain,
                sender_name=current_user.name or current_user.email,
                message=payload.body,
                thread_url=thread_url,
            )
    except Exception as e:
        logger.error(f"Failed to send listing message notification: {e}")

    await db.commit()
    await db.refresh(msg)
    return InquiryMessageResponse.model_validate(msg)


@router.put("/{id}", response_model=ListingResponse)
async def update_listing(
    id: int,
    data: ListingUpdate,
    request: Request,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Update a listing."""
    result = await db.execute(
        select(DomainListing).where(
            and_(
                DomainListing.id == id,
                DomainListing.user_id == current_user.id,
            )
        )
    )
    listing = result.scalar_one_or_none()
    
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")
    
    # Update fields
    if data.title is not None:
        listing.title = data.title
    if data.description is not None:
        listing.description = data.description
    if data.asking_price is not None:
        listing.asking_price = data.asking_price
    if data.min_offer is not None:
        listing.min_offer = data.min_offer
    if data.price_type is not None:
        listing.price_type = data.price_type
    if data.show_valuation is not None:
        listing.show_valuation = data.show_valuation
    if data.allow_offers is not None:
        listing.allow_offers = data.allow_offers
    
    # Status change
    if data.status is not None:
        if data.status == "active" and listing.status == "draft":
            # Publish listing
            if not listing.is_verified:
                raise HTTPException(
                    status_code=400,
                    detail="Cannot publish without DNS verification"
                )
            listing.status = ListingStatus.ACTIVE.value
            listing.published_at = datetime.utcnow()
        elif data.status in ["draft", "expired"]:
            listing.status = data.status
        elif data.status == "sold":
            if listing.status != ListingStatus.ACTIVE.value:
                raise HTTPException(status_code=400, detail="Only active listings can be marked as sold.")
            listing.status = ListingStatus.SOLD.value
            listing.sold_at = datetime.utcnow()
            listing.sold_reason = (data.sold_reason or "").strip() or listing.sold_reason
            listing.sold_price = data.sold_price if data.sold_price is not None else listing.sold_price
            listing.sold_currency = (data.sold_currency or listing.currency or "USD").upper()

            # Close all open inquiries on this listing (deal is done).
            inqs = (
                await db.execute(
                    select(ListingInquiry).where(ListingInquiry.listing_id == listing.id)
                )
            ).scalars().all()
            for inq in inqs:
                if inq.status in ["closed", "spam"]:
                    continue
                old = inq.status
                inq.status = "closed"
                inq.closed_at = datetime.utcnow()
                inq.closed_reason = inq.closed_reason or "sold"
                db.add(
                    ListingInquiryEvent(
                        inquiry_id=inq.id,
                        listing_id=listing.id,
                        actor_user_id=current_user.id,
                        old_status=old,
                        new_status="closed",
                        reason="sold",
                        ip_address=request.client.host if request.client else None,
                        user_agent=request.headers.get("user-agent", "")[:500],
                    )
                )

            await track_event(
                db,
                event_name="listing_marked_sold",
                request=request,
                user_id=current_user.id,
                is_authenticated=True,
                source="terminal",
                domain=listing.domain,
                listing_id=listing.id,
                metadata={
                    "sold_reason": listing.sold_reason,
                    "sold_price": float(listing.sold_price) if listing.sold_price is not None else None,
                    "sold_currency": listing.sold_currency,
                },
            )
    
    await db.commit()
    await db.refresh(listing)
    
    return ListingResponse(
        id=listing.id,
        domain=listing.domain,
        slug=listing.slug,
        title=listing.title,
        description=listing.description,
        asking_price=listing.asking_price,
        min_offer=listing.min_offer,
        currency=listing.currency,
        price_type=listing.price_type,
        pounce_score=listing.pounce_score,
        estimated_value=listing.estimated_value,
        verification_status=listing.verification_status,
        is_verified=listing.is_verified,
        status=listing.status,
        show_valuation=listing.show_valuation,
        allow_offers=listing.allow_offers,
        view_count=listing.view_count,
        inquiry_count=listing.inquiry_count,
        public_url=listing.public_url,
        created_at=listing.created_at,
        published_at=listing.published_at,
        sold_at=getattr(listing, "sold_at", None),
        sold_reason=getattr(listing, "sold_reason", None),
        sold_price=getattr(listing, "sold_price", None),
        sold_currency=getattr(listing, "sold_currency", None),
        seller_verified=current_user.is_verified,
        seller_member_since=current_user.created_at,
    )


@router.delete("/{id}")
async def delete_listing(
    id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Delete a listing."""
    result = await db.execute(
        select(DomainListing).where(
            and_(
                DomainListing.id == id,
                DomainListing.user_id == current_user.id,
            )
        )
    )
    listing = result.scalar_one_or_none()
    
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")
    
    await db.delete(listing)
    await db.commit()
    
    return {"success": True, "message": "Listing deleted"}


@router.post("/{id}/verify-dns", response_model=VerificationResponse)
async def start_dns_verification(
    id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Start DNS verification for a listing."""
    result = await db.execute(
        select(DomainListing).where(
            and_(
                DomainListing.id == id,
                DomainListing.user_id == current_user.id,
            )
        )
    )
    listing = result.scalar_one_or_none()
    
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")
    
    # Generate new code if needed
    if not listing.verification_code:
        listing.verification_code = _generate_verification_code()
    
    listing.verification_status = VerificationStatus.PENDING.value
    await db.commit()
    
    # Extract domain root for DNS
    domain_parts = listing.domain.split('.')
    if len(domain_parts) > 2:
        dns_name = f"_pounce.{'.'.join(domain_parts[-2:])}"
    else:
        dns_name = f"_pounce.{listing.domain}"
    
    return VerificationResponse(
        verification_code=listing.verification_code,
        dns_record_type="TXT",
        dns_record_name=dns_name,
        dns_record_value=listing.verification_code,
        instructions=f"""
To verify ownership of {listing.domain}:

1. Go to your domain registrar's DNS settings
2. Add a new TXT record:
   - Name/Host: _pounce (or _pounce.{listing.domain})
   - Value: {listing.verification_code}
   - TTL: 300 (or lowest available)
3. Wait 1-5 minutes for DNS propagation
4. Click "Check Verification" to complete

This proves you control the domain's DNS, confirming ownership.
        """.strip(),
        status=listing.verification_status,
    )


@router.get("/{id}/verify-dns/check")
async def check_dns_verification(
    id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Check DNS verification status."""
    result = await db.execute(
        select(DomainListing).where(
            and_(
                DomainListing.id == id,
                DomainListing.user_id == current_user.id,
            )
        )
    )
    listing = result.scalar_one_or_none()
    
    if not listing:
        raise HTTPException(status_code=404, detail="Listing not found")
    
    if not listing.verification_code:
        raise HTTPException(status_code=400, detail="Start verification first")
    
    # Check DNS TXT record
    import dns.resolver
    
    try:
        domain_parts = listing.domain.split('.')
        if len(domain_parts) > 2:
            dns_name = f"_pounce.{'.'.join(domain_parts[-2:])}"
        else:
            dns_name = f"_pounce.{listing.domain}"
        
        answers = dns.resolver.resolve(dns_name, 'TXT')
        
        for rdata in answers:
            txt_value = str(rdata).strip('"')
            if txt_value == listing.verification_code:
                # Verified!
                listing.verification_status = VerificationStatus.VERIFIED.value
                listing.verified_at = datetime.utcnow()
                await db.commit()
                
                return {
                    "verified": True,
                    "status": "verified",
                    "message": "DNS verification successful! You can now publish your listing.",
                }
        
        # Code not found
        return {
            "verified": False,
            "status": "pending",
            "message": "TXT record found but value doesn't match. Please check the value.",
        }
        
    except dns.resolver.NXDOMAIN:
        return {
            "verified": False,
            "status": "pending",
            "message": "DNS record not found. Please add the TXT record and wait for propagation.",
        }
    except dns.resolver.NoAnswer:
        return {
            "verified": False,
            "status": "pending",
            "message": "No TXT record found. Please add the record.",
        }
    except Exception as e:
        logger.error(f"DNS check failed for {listing.domain}: {e}")
        return {
            "verified": False,
            "status": "error",
            "message": "DNS check failed. Please try again in a few minutes.",
        }


# ============== Inbox API (Unified Buyer + Seller) ==============

@router.get("/inbox/counts")
async def get_inbox_counts(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    Get unread message/inquiry counts for both Buyer and Seller roles.
    Used for badge display in navigation.
    """
    # BUYER: Count inquiries where there are unread seller messages
    # A message is "unread" for buyer if sender_user_id != buyer_user_id and no newer message from buyer
    buyer_inquiries = await db.execute(
        select(ListingInquiry).where(ListingInquiry.buyer_user_id == current_user.id)
    )
    buyer_inqs = list(buyer_inquiries.scalars().all())
    
    buyer_unread = 0
    for inq in buyer_inqs:
        # Get the latest message
        latest_msg = await db.execute(
            select(ListingInquiryMessage)
            .where(ListingInquiryMessage.inquiry_id == inq.id)
            .order_by(ListingInquiryMessage.created_at.desc())
            .limit(1)
        )
        msg = latest_msg.scalar_one_or_none()
        # If latest message is from seller (not buyer), it's unread
        if msg and msg.sender_user_id != current_user.id:
            buyer_unread += 1
    
    # SELLER: Count new/unread inquiries across all listings
    seller_listings = await db.execute(
        select(DomainListing.id).where(DomainListing.user_id == current_user.id)
    )
    listing_ids = [lid for (lid,) in seller_listings.fetchall()]
    
    seller_unread = 0
    if listing_ids:
        # Count inquiries that are 'new' (never read)
        new_count = await db.execute(
            select(func.count(ListingInquiry.id)).where(
                and_(
                    ListingInquiry.listing_id.in_(listing_ids),
                    ListingInquiry.status == "new",
                )
            )
        )
        seller_unread = new_count.scalar() or 0
        
        # Also count inquiries where latest message is from buyer (unread reply)
        for lid in listing_ids:
            inqs_result = await db.execute(
                select(ListingInquiry).where(
                    and_(
                        ListingInquiry.listing_id == lid,
                        ListingInquiry.status.notin_(["closed", "spam"]),
                    )
                )
            )
            for inq in inqs_result.scalars().all():
                if inq.status == "new":
                    continue  # Already counted
                latest_msg = await db.execute(
                    select(ListingInquiryMessage)
                    .where(ListingInquiryMessage.inquiry_id == inq.id)
                    .order_by(ListingInquiryMessage.created_at.desc())
                    .limit(1)
                )
                msg = latest_msg.scalar_one_or_none()
                # If latest message is from buyer (not seller), it's unread for seller
                if msg and msg.sender_user_id != current_user.id:
                    seller_unread += 1
    
    return {
        "buyer_unread": buyer_unread,
        "seller_unread": seller_unread,
        "total_unread": buyer_unread + seller_unread,
    }


@router.get("/inbox/seller")
async def get_seller_inbox(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    status_filter: Optional[str] = Query(None, enum=["all", "new", "read", "replied", "closed", "spam"]),
):
    """
    Seller Inbox: Get all inquiries across all listings owned by the current user.
    This provides a unified inbox view for sellers.
    """
    # Get all listings owned by user
    listings_result = await db.execute(
        select(DomainListing).where(DomainListing.user_id == current_user.id)
    )
    listings = {l.id: l for l in listings_result.scalars().all()}
    
    if not listings:
        return {"inquiries": [], "total": 0, "unread": 0}
    
    # Build query for inquiries
    query = (
        select(ListingInquiry)
        .where(ListingInquiry.listing_id.in_(listings.keys()))
        .order_by(ListingInquiry.created_at.desc())
    )
    
    if status_filter and status_filter != "all":
        query = query.where(ListingInquiry.status == status_filter)
    
    result = await db.execute(query)
    inquiries = list(result.scalars().all())
    
    # Count unread
    unread_count = sum(1 for inq in inquiries if inq.status == "new" or not inq.read_at)
    
    # Build response with listing info
    response_items = []
    for inq in inquiries:
        listing = listings.get(inq.listing_id)
        if not listing:
            continue
        
        # Get latest message for preview
        latest_msg_result = await db.execute(
            select(ListingInquiryMessage)
            .where(ListingInquiryMessage.inquiry_id == inq.id)
            .order_by(ListingInquiryMessage.created_at.desc())
            .limit(1)
        )
        latest_msg = latest_msg_result.scalar_one_or_none()
        
        # Check if has unread reply from buyer
        has_unread_reply = False
        if latest_msg and latest_msg.sender_user_id != current_user.id and inq.status not in ["closed", "spam"]:
            has_unread_reply = True
        
        response_items.append({
            "id": inq.id,
            "listing_id": listing.id,
            "domain": listing.domain,
            "slug": listing.slug,
            "buyer_name": inq.name,
            "buyer_email": inq.email,
            "offer_amount": inq.offer_amount,
            "status": inq.status,
            "created_at": inq.created_at.isoformat(),
            "read_at": inq.read_at.isoformat() if inq.read_at else None,
            "replied_at": getattr(inq, "replied_at", None),
            "closed_at": inq.closed_at.isoformat() if getattr(inq, "closed_at", None) else None,
            "closed_reason": getattr(inq, "closed_reason", None),
            "has_unread_reply": has_unread_reply,
            "last_message_preview": (latest_msg.body[:100] + "..." if len(latest_msg.body) > 100 else latest_msg.body) if latest_msg else inq.message[:100],
            "last_message_at": latest_msg.created_at.isoformat() if latest_msg else inq.created_at.isoformat(),
            "last_message_is_buyer": latest_msg.sender_user_id != current_user.id if latest_msg else True,
        })
    
    return {
        "inquiries": response_items,
        "total": len(response_items),
        "unread": unread_count,
    }

