from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import or_, select
from sqlalchemy.orm import Session

from app.api.workspace import get_verified_current_user
from app.core.permissions import Permission
from app.db.session import get_db
from app.models.customer import Customer
from app.models.invoice import Invoice
from app.models.membership import Membership, MembershipBranch
from app.models.product import Product
from app.models.purchase import Purchase
from app.models.quote import Quote
from app.models.sale import Sale
from app.models.supplier import Supplier
from app.models.user import User
from app.services.rbac import require_permission


router = APIRouter(tags=["Global Search"])


@router.get("/api/businesses/{business_id}/search")
def search(
    business_id: UUID,
    q: str = Query(min_length=2, max_length=100),
    limit: int = Query(default=40, ge=1, le=80),
    user: User = Depends(get_verified_current_user),
    db: Session = Depends(get_db),
):
    member = require_permission(
        db,
        user,
        business_id,
        Permission.OPERATE_SALES,
    )

    query_text = q.strip()

    if len(query_text) < 2:
        raise HTTPException(
            422,
            "Search term must contain at least two characters.",
        )

    term = f"%{query_text}%"

    branch_ids = (
        None
        if member.all_branches
        else list(
            db.scalars(
                select(MembershipBranch.branch_id).where(
                    MembershipBranch.membership_id == member.id
                )
            )
        )
    )

    # Eight supported resource families.
    per_type = max(1, min(10, limit // 8 or 1))

    results: list[dict] = []

    products = db.scalars(
        select(Product)
        .where(
            Product.business_id == business_id,
            or_(
                Product.name.ilike(term),
                Product.sku.ilike(term),
                Product.barcode.ilike(term),
            ),
        )
        .limit(per_type)
    )

    results += [
        {
            "resource_type": "product",
            "id": row.id,
            "display": row.name,
            "secondary": row.sku or row.barcode or "",
        }
        for row in products
    ]

    customers = db.scalars(
        select(Customer)
        .where(
            Customer.business_id == business_id,
            or_(
                Customer.name.ilike(term),
                Customer.phone.ilike(term),
                Customer.email.ilike(term),
            ),
        )
        .limit(per_type)
    )

    results += [
        {
            "resource_type": "customer",
            "id": row.id,
            "display": row.name,
            "secondary": row.phone or row.email or "",
        }
        for row in customers
    ]

    suppliers = db.scalars(
        select(Supplier)
        .where(
            Supplier.business_id == business_id,
            or_(
                Supplier.name.ilike(term),
                Supplier.phone.ilike(term),
                Supplier.email.ilike(term),
            ),
        )
        .limit(per_type)
    )

    results += [
        {
            "resource_type": "supplier",
            "id": row.id,
            "display": row.name,
            "secondary": row.phone or row.email or "",
        }
        for row in suppliers
    ]

    sales = select(Sale).where(
        Sale.business_id == business_id,
        Sale.receipt_number.ilike(term),
    )

    purchases = select(Purchase).where(
        Purchase.business_id == business_id,
        Purchase.reference_number.ilike(term),
    )

    invoices = select(Invoice).where(
        Invoice.business_id == business_id,
        Invoice.invoice_number.ilike(term),
    )

    quotes = select(Quote).where(
        Quote.business_id == business_id,
        Quote.quote_number.ilike(term),
    )

    if branch_ids is not None:
        sales = sales.where(Sale.branch_id.in_(branch_ids))
        purchases = purchases.where(
            Purchase.branch_id.in_(branch_ids)
        )
        invoices = invoices.where(
            Invoice.branch_id.in_(branch_ids)
        )
        quotes = quotes.where(
            Quote.branch_id.in_(branch_ids)
        )

    results += [
        {
            "resource_type": "sale",
            "id": row.id,
            "display": row.receipt_number,
            "secondary": str(row.total),
        }
        for row in db.scalars(sales.limit(per_type))
    ]

    results += [
        {
            "resource_type": "purchase",
            "id": row.id,
            "display": row.reference_number,
            "secondary": str(row.total),
        }
        for row in db.scalars(purchases.limit(per_type))
    ]

    results += [
        {
            "resource_type": "invoice",
            "id": row.id,
            "display": row.invoice_number,
            "secondary": str(row.total),
        }
        for row in db.scalars(invoices.limit(per_type))
    ]

    results += [
        {
            "resource_type": "quote",
            "id": row.id,
            "display": row.quote_number,
            "secondary": str(row.total),
        }
        for row in db.scalars(quotes.limit(per_type))
    ]

    # Staff information follows the stricter MANAGE_STAFF permission.
    can_search_staff = True

    try:
        require_permission(
            db,
            user,
            business_id,
            Permission.MANAGE_STAFF,
        )
    except HTTPException as exc:
        if exc.status_code == 403:
            can_search_staff = False
        else:
            raise

    if can_search_staff:
        staff_query = (
            select(Membership, User)
            .join(User, User.id == Membership.user_id)
            .where(
                Membership.business_id == business_id,
                or_(
                    User.full_name.ilike(term),
                    User.email.ilike(term),
                ),
            )
            .limit(per_type)
        )

        for membership, staff_user in db.execute(staff_query):
            results.append(
                {
                    "resource_type": "staff",
                    "id": membership.id,
                    "display": (
                        staff_user.full_name
                        or staff_user.email
                    ),
                    "secondary": (
                        f"{membership.role} ? "
                        f"{staff_user.email} ? "
                        f"{'Active' if membership.is_active else 'Inactive'}"
                    ),
                }
            )

    return {
        "query": query_text,
        "results": results[:limit],
    }
