from __future__ import annotations


class InquiryService:
    @staticmethod
    async def _invalidate_new_count_cache(tenant_id) -> None:
        """Bust the Redis-cached unread count so the Sales > Inbox badge stays accurate after writes."""
        try:
            import redis.asyncio as aioredis
            from src.core.config import settings
            r = aioredis.from_url(settings.REDIS_URL, decode_responses=True)
            await r.delete(f"count:inquiries-new:{tenant_id}")
            await r.aclose()
        except Exception:
            pass  # Redis unavailable — cache will simply expire on its own TTL

    @staticmethod
    async def _next_reference_id(db, tenant_id) -> str:
        """Generate INQ-YYYY-NNNN reference."""
        from datetime import datetime, timezone
        from sqlalchemy import func, select
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        year = datetime.now(timezone.utc).year
        count_result = await db.execute(
            select(func.count()).select_from(ContactInquiry).where(
                ContactInquiry.tenant_id == tenant_id
            )
        )
        n = count_result.scalar_one() + 1
        return f"INQ-{year}-{n:04d}"

    @staticmethod
    async def create_availability_enquiry(db, tenant_id, body, ip_address=None, user_agent=None):
        """Create a plot_availability inquiry from the public portal."""
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        ref = await InquiryService._next_reference_id(db, tenant_id)
        inq = ContactInquiry(
            tenant_id=tenant_id,
            reference_id=ref,
            source_type="plot_availability",
            sender_name=body.sender_name,
            sender_email=str(body.sender_email),
            sender_phone=body.sender_phone,
            message=body.message,
            plot_number=body.plot_number,
            section_name=body.section_name,
            listed_price=body.listed_price,
            ip_address=ip_address,
            user_agent=user_agent,
            status="new",
        )
        db.add(inq)
        await db.flush()
        await InquiryService._invalidate_new_count_cache(tenant_id)
        return inq

    @staticmethod
    async def create_cemetery_contact(db, tenant_id, body, ip_address=None, user_agent=None):
        """Create a contact_form inquiry from the public cemetery contact form (INDL-24)."""
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        ref = await InquiryService._next_reference_id(db, tenant_id)
        inq = ContactInquiry(
            tenant_id=tenant_id,
            reference_id=ref,
            source_type="contact_form",
            topic=body.topic,
            sender_name=body.sender_name,
            sender_email=str(body.sender_email),
            sender_phone=body.sender_phone,
            person_or_plot=body.person_or_plot,
            message=body.message,
            subscribe_newsletter=body.subscribe_newsletter,
            ip_address=ip_address,
            user_agent=user_agent,
            status="new",
        )
        db.add(inq)
        await db.flush()
        await InquiryService._invalidate_new_count_cache(tenant_id)
        return inq

    @staticmethod
    async def count_new(db, tenant_id) -> int:
        """Lightweight count of unread ('new') inquiries for a tenant."""
        from sqlalchemy import func, select
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        result = await db.execute(
            select(func.count()).select_from(ContactInquiry).where(
                ContactInquiry.tenant_id == tenant_id,
                ContactInquiry.status == "new",
            )
        )
        return result.scalar_one()

    @staticmethod
    async def log_call(db, tenant_id, body, current_user):
        """Create a call_booking inquiry logged by staff."""
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        ref = await InquiryService._next_reference_id(db, tenant_id)
        inq = ContactInquiry(
            tenant_id=tenant_id,
            reference_id=ref,
            source_type="call_booking",
            sender_name=body.sender_name,
            sender_phone=body.sender_phone,
            message=body.notes,
            notes=body.notes,
            call_date=body.call_date,
            agent_name=body.agent_name,
            created_by_user_id=current_user.id,
            status="new",
        )
        db.add(inq)
        await db.flush()
        await InquiryService._invalidate_new_count_cache(tenant_id)
        return inq

    @staticmethod
    async def log_email(db, tenant_id, body, current_user):
        """Create an email inquiry logged by staff."""
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        ref = await InquiryService._next_reference_id(db, tenant_id)
        inq = ContactInquiry(
            tenant_id=tenant_id,
            reference_id=ref,
            source_type="email",
            sender_name=body.sender_name,
            sender_email=str(body.sender_email),
            message=body.message,
            email_subject=body.email_subject,
            email_received_at=body.email_received_at,
            created_by_user_id=current_user.id,
            status="new",
        )
        db.add(inq)
        await db.flush()
        await InquiryService._invalidate_new_count_cache(tenant_id)
        return inq

    @staticmethod
    async def list_inquiries(db, tenant_id, status=None, page=1, page_size=20):
        """List all inquiries for a tenant, newest first."""
        from sqlalchemy import select, func
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        filters = [ContactInquiry.tenant_id == tenant_id]
        if status:
            filters.append(ContactInquiry.status == status)
        total = (await db.execute(
            select(func.count()).select_from(ContactInquiry).where(*filters)
        )).scalar_one()
        offset = (page - 1) * page_size
        result = await db.execute(
            select(ContactInquiry)
            .where(*filters)
            .order_by(ContactInquiry.created_at.desc())
            .offset(offset).limit(page_size)
        )
        return result.scalars().all(), total

    @staticmethod
    async def get_by_id(db, tenant_id, inquiry_id):
        """Get inquiry by ID, enforcing tenant scope."""
        from sqlalchemy import select
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        from fastapi import HTTPException
        result = await db.execute(
            select(ContactInquiry).where(
                ContactInquiry.id == inquiry_id,
                ContactInquiry.tenant_id == tenant_id,
            )
        )
        inq = result.scalar_one_or_none()
        if not inq:
            raise HTTPException(status_code=404, detail="Inquiry not found")
        return inq

    @staticmethod
    async def update_inquiry(db, tenant_id, inquiry_id, data: dict):
        """Update inquiry fields (status, log edits)."""
        inq = await InquiryService.get_by_id(db, tenant_id, inquiry_id)
        allowed = {
            "status", "sender_name", "sender_phone", "sender_email",
            "call_date", "agent_name", "notes",
            "email_subject", "email_received_at", "message",
        }
        for k, v in data.items():
            if k in allowed and v is not None:
                setattr(inq, k, v)
        await db.flush()
        if "status" in data:
            await InquiryService._invalidate_new_count_cache(tenant_id)
        return inq

    @staticmethod
    async def convert_to_opportunity(db, tenant_id, inquiry_id, current_user):
        """Convert inquiry to a sales opportunity."""
        from src.apps.sales.models.contact_inquiry import ContactInquiry
        from src.apps.sales.models.opportunity import Opportunity
        inq = await InquiryService.get_by_id(db, tenant_id, inquiry_id)
        opp = Opportunity(
            tenant_id=tenant_id,
            family_name=inq.sender_name,
            contact_email=inq.sender_email,
            contact_phone=inq.sender_phone,
            stage="inquiry",
            notes=inq.message or "",
            estimated_value=inq.listed_price or 0,
        )
        db.add(opp)
        await db.flush()
        inq.status = "converted"
        inq.converted_opportunity_id = opp.id
        await db.flush()
        await InquiryService._invalidate_new_count_cache(tenant_id)
        return inq, opp
