"""Tax rate lookup endpoints — proxy TaxJar through a DB-backed cache."""
from typing import Optional, List

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

from src.core.database import get_db
from src.core.config import settings as app_settings
from src.apps.auth.utils.auth import get_current_merchant
from src.apps.tax.taxjar_client import TaxJarClient
from src.apps.tax.schemas import TaxRateResponse, TaxSearchResponse, TaxSearchResult
from src.apps.tax import services as tax_services

router = APIRouter()


def _require_key() -> TaxJarClient:
    """Return a configured TaxJarClient or raise 503 if the key is not set."""
    if not app_settings.TAXJAR_API_KEY:
        raise HTTPException(status_code=503, detail="Tax lookup is not available")
    return TaxJarClient(app_settings.TAXJAR_API_KEY, app_settings.TAXJAR_BASE_URL)


# ── Merchant-facing endpoints ─────────────────────────────────────────────────

@router.get("/rates", response_model=TaxRateResponse)
async def get_tax_rate(
    zip: str = Query(..., min_length=3, max_length=10),
    city: Optional[str] = Query(default=None),
    state: Optional[str] = Query(default=None),
    country: str = Query(default="US"),
    _merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """Look up the combined sales tax rate for a zip/city/state location.
    Results are served from DB cache; TaxJar is only called on a miss or expiry.
    """
    if not app_settings.TAXJAR_API_KEY:
        raise HTTPException(status_code=503, detail="Tax lookup is not available")
    try:
        return await tax_services.get_rate_cached(zip, city, state, country, db)
    except httpx.HTTPStatusError as e:
        raise HTTPException(status_code=502, detail=f"TaxJar error: {e.response.text}")
    except Exception as e:
        raise HTTPException(status_code=502, detail=f"TaxJar unavailable: {str(e)}")


@router.get("/search", response_model=TaxSearchResponse)
async def search_tax_rates(
    q: str = Query(..., min_length=3, max_length=50),
    _merchant=Depends(get_current_merchant),
    db: Session = Depends(get_db),
):
    """Autocomplete tax rate search.
    - 5-digit numeric query → direct zip lookup via /rates.
    - 3+ character string → city-prefix search using uszipcode, then resolve rates.
    """
    _require_key()
    results: List[TaxSearchResult] = []

    stripped = q.strip()
    if stripped.isdigit() and len(stripped) <= 10:
        # Exact-ish zip lookup
        try:
            rate = await tax_services.get_rate_cached(stripped, None, None, "US", db)
            results = [TaxSearchResult(**rate.model_dump())]
        except Exception:
            pass
    else:
        # City-prefix search via uszipcode (Option A — local lookup)
        results = await _city_search(stripped, db)

    return TaxSearchResponse(results=results)


async def _city_search(prefix: str, db: Session) -> List[TaxSearchResult]:
    """Search cities by prefix using the local uszipcode database,
    resolve the first 5 unique zip codes through the TaxJar cache,
    and return up to 10 results.
    """
    from uszipcode import SearchEngine  # lazy import — only needed for city search

    results: List[TaxSearchResult] = []
    try:
        with SearchEngine() as engine:
            matches = engine.by_city_and_state(city=prefix, state=None, returns=20)
            if not matches:
                # Try prefix search on city name
                matches = engine.by_prefix(prefix, returns=20)

        seen_zips: set = set()
        for m in matches:
            if len(results) >= 10:
                break
            zip_code = str(m.zipcode)
            if zip_code in seen_zips:
                continue
            seen_zips.add(zip_code)
            try:
                rate = await tax_services.get_rate_cached(
                    zip_code, m.major_city, m.state, "US", db
                )
                results.append(TaxSearchResult(**rate.model_dump()))
            except Exception:
                continue
    except Exception:
        pass

    return results


# Note: Admin cache-management endpoints (DELETE /admin/tax-cache, DELETE /admin/tax-cache/{zip})
# are registered in src/apps/admin/router.py so they live under the standard /admin prefix.
