import json
import time
import requests as http_requests

from django.contrib.admin.views.decorators import staff_member_required
from django.conf import settings as django_settings
from django.http import JsonResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.utils.text import slugify
from django.views.decorators.http import require_POST

from .models import ACASettings, StoreRegistry, StoreHealthLog
from vendors.models import Vendor, VendorProduct
from vendors.models import VendorSubscription
from django.db.models import Count, Q

@staff_member_required
def dashboard(request):
    """Main dashboard — lists all connected stores with health stats."""
    stores = StoreRegistry.objects.all()
    store_data = []
    for store in stores:
        last_health = store.health_logs.first()
        recent_logs = store.health_logs.all()[:20]
        success_count = sum(1 for l in recent_logs if l.success)
        total = len(recent_logs)
        uptime = round((success_count / total) * 100) if total else None

        store_data.append({
            "store": store,
            "last_health": last_health,
            "uptime": uptime,
            "total_checks": total,
        })

    return render(request, "stores/dashboard.html", {
        "store_data": store_data,
        "total_stores": stores.count(),
        "active_stores": stores.filter(is_active=True).count(),
    })


@staff_member_required
def store_add(request):
    """Add a new store — enter domain, auto-detect, confirm."""
    if request.method == "POST":
        data = request.POST
        name = data.get("name", "").strip()
        base_api_url = data.get("base_api_url", "").strip()

        if not name or not base_api_url:
            return render(request, "stores/store_add.html", {
                "error": "Store name and API URL are required.",
                "form_data": data,
            })

        slug = slugify(name)
        if StoreRegistry.objects.filter(slug=slug).exists():
            return render(request, "stores/store_add.html", {
                "error": "A store with this name already exists.",
                "form_data": data,
            })

        StoreRegistry.objects.create(
            name=name,
            slug=slug,
            base_api_url=base_api_url,
            search_endpoint=data.get("search_endpoint", "aca/products/search/"),
            detail_endpoint=data.get("detail_endpoint", "aca/products/"),
            auth_method=data.get("auth_method", "none"),
            api_key=data.get("api_key", ""),
            auth_header_name=data.get("auth_header_name", "X-Api-Key"),
            logo=data.get("logo", ""),
            priority=int(data.get("priority", 0)),
            is_active=True,
            response_mapping=_parse_json(data.get("response_mapping", "{}")),
        )
        return redirect("stores:dashboard")

    return render(request, "stores/store_add.html", {})


@staff_member_required
def store_edit(request, store_id):
    """Edit an existing store."""
    store = get_object_or_404(StoreRegistry, id=store_id)

    if request.method == "POST":
        data = request.POST
        name = data.get("name", "").strip()
        base_api_url = data.get("base_api_url", "").strip()

        if not name or not base_api_url:
            return render(request, "stores/store_edit.html", {
                "error": "Store name and API URL are required.",
                "store": store,
            })

        slug = slugify(name)
        if StoreRegistry.objects.filter(slug=slug).exclude(id=store.id).exists():
            return render(request, "stores/store_edit.html", {
                "error": "A store with this name already exists.",
                "store": store,
            })

        store.name = name
        store.slug = slug
        store.base_api_url = base_api_url
        store.search_endpoint = data.get("search_endpoint", store.search_endpoint)
        store.detail_endpoint = data.get("detail_endpoint", store.detail_endpoint)
        store.auth_method = data.get("auth_method", store.auth_method)
        store.api_key = data.get("api_key", store.api_key)
        store.auth_header_name = data.get("auth_header_name", store.auth_header_name)
        store.logo = data.get("logo", store.logo)
        store.priority = int(data.get("priority", store.priority))
        store.is_active = data.get("is_active") == "on"
        store.response_mapping = _parse_json(data.get("response_mapping", "{}"))
        store.save()
        return redirect("stores:dashboard")

    return render(request, "stores/store_edit.html", {"store": store})


@staff_member_required
@require_POST
def store_delete(request, store_id):
    store = get_object_or_404(StoreRegistry, id=store_id)
    store.delete()
    return redirect("stores:dashboard")


@staff_member_required
@require_POST
def store_toggle(request, store_id):
    store = get_object_or_404(StoreRegistry, id=store_id)
    store.is_active = not store.is_active
    store.save(update_fields=["is_active"])
    if request.headers.get("X-Requested-With") == "XMLHttpRequest":
        return JsonResponse({"is_active": store.is_active})
    return redirect("stores:dashboard")


@staff_member_required
def store_test(request, store_id):
    """Test connectivity to a store's search endpoint."""
    store = get_object_or_404(StoreRegistry, id=store_id)
    result = _ping_store(store)
    return JsonResponse(result)


@staff_member_required
def store_probe(request):
    """
    AJAX endpoint: given a domain URL, probe it for ACA store-info.
    Tries {url}/api/aca/store-info/ to auto-detect store details.
    """
    domain = request.GET.get("url", "").strip().rstrip("/")
    if not domain:
        return JsonResponse({"success": False, "error": "No URL provided"})

    candidates = []
    if "/api" in domain:
        candidates.append(domain.rstrip("/") + "/aca/store-info/")
    else:
        candidates.append(domain + "/api/aca/store-info/")
        candidates.append(domain + "/aca/store-info/")

    for probe_url in candidates:
        try:
            start = time.monotonic()
            resp = http_requests.get(probe_url, timeout=8, headers={"Accept": "application/json"})
            elapsed = int((time.monotonic() - start) * 1000)

            if resp.ok:
                data = resp.json()
                if data.get("aca_compatible"):
                    base_api_url = probe_url.rsplit("/aca/store-info", 1)[0]
                    if not base_api_url.endswith("/"):
                        base_api_url += "/"

                    endpoints = data.get("endpoints", {})
                    return JsonResponse({
                        "success": True,
                        "store_name": data.get("store_name", ""),
                        "store_tagline": data.get("store_tagline", ""),
                        "store_description": data.get("store_description", ""),
                        "logo_url": data.get("logo_url", ""),
                        "total_products": data.get("total_products", 0),
                        "categories": data.get("categories", []),
                        "base_api_url": base_api_url,
                        "search_endpoint": endpoints.get("search", "aca/products/search/"),
                        "detail_endpoint": endpoints.get("detail", "aca/products/"),
                        "response_time_ms": elapsed,
                    })
        except Exception:
            continue

    return JsonResponse({
        "success": False,
        "error": "Could not detect an ACA-compatible store at this URL. Make sure the store has ACA endpoints enabled.",
    })


@staff_member_required
def aca_settings(request):
    """View / update ACA platform settings (provider, API keys, model config, subscriptions)."""
    from .models import ACASettings
    from vendors.models import VendorSubscription
 
    settings_obj = ACASettings.load()
 
    # Env-level overrides (take priority over DB)
    import django.conf as _djconf
    env_claude_key = getattr(_djconf.settings, "ANTHROPIC_API_KEY", "")
    env_openai_key = getattr(_djconf.settings, "OPENAI_API_KEY", "")
 
    def _mask(k):
        if not k:
            return ""
        if len(k) <= 12:
            return "****"
        return k[:8] + "****" + k[-4:]
 
    effective_claude_masked = _mask(env_claude_key) if env_claude_key else settings_obj.masked_key
    effective_openai_masked = _mask(env_openai_key) if env_openai_key else settings_obj.masked_openai_key
 
    claude_active = bool(env_claude_key) or bool(settings_obj.anthropic_api_key)
    openai_active = bool(env_openai_key) or bool(settings_obj.openai_api_key)
 
    # Overall AI active: the *selected* provider has a key
    if settings_obj.llm_provider == "openai":
        ai_active = openai_active
    else:
        ai_active = claude_active
 
    # Subscription counts
    active_subscriptions = VendorSubscription.objects.filter(status__in=["active", "free"]).count()
    expired_subscriptions = VendorSubscription.objects.filter(status="expired").count()
    pending_subscriptions = VendorSubscription.objects.filter(status="pending_payment").count()
 
    if request.method == "POST":
        # ── Provider toggle ──────────────────────────────────────────────
        provider = request.POST.get("llm_provider", "").strip()
        if provider in ("claude", "openai"):
            settings_obj.llm_provider = provider
 
        # ── Claude key ──────────────────────────────────────────────────
        new_claude_key = request.POST.get("anthropic_api_key", "").strip()
        if new_claude_key and "****" not in new_claude_key:
            settings_obj.anthropic_api_key = new_claude_key
 
        model = request.POST.get("llm_model", "").strip()
        if model:
            settings_obj.llm_model = model
 
        max_tokens = request.POST.get("llm_max_tokens", "")
        if max_tokens.isdigit():
            settings_obj.llm_max_tokens = int(max_tokens)
 
        # ── OpenAI key ───────────────────────────────────────────────────
        new_openai_key = request.POST.get("openai_api_key", "").strip()
        if new_openai_key and "****" not in new_openai_key:
            settings_obj.openai_api_key = new_openai_key
 
        openai_model = request.POST.get("openai_model", "").strip()
        if openai_model:
            settings_obj.openai_model = openai_model
 
        # ── Vendor subscription fields ───────────────────────────────────
        fee_str = request.POST.get("vendor_registration_fee", "").strip()
        try:
            from decimal import Decimal
            settings_obj.vendor_registration_fee = (
                Decimal(fee_str) if fee_str else settings_obj.vendor_registration_fee
            )
        except Exception:
            pass
 
        sub_months_str = request.POST.get("vendor_subscription_months", "").strip()
        if sub_months_str.isdigit():
            settings_obj.vendor_subscription_months = int(sub_months_str)
 
        settings_obj.vendor_registration_free = request.POST.get("vendor_registration_free") == "on"
 
        free_dur_str = request.POST.get("vendor_free_duration_months", "").strip()
        if free_dur_str.isdigit():
            settings_obj.vendor_free_duration_months = int(free_dur_str)
 
        settings_obj.save()
 
        # Recompute masked / active after save
        effective_claude_masked = _mask(env_claude_key) if env_claude_key else settings_obj.masked_key
        effective_openai_masked = _mask(env_openai_key) if env_openai_key else settings_obj.masked_openai_key
        claude_active = bool(env_claude_key) or bool(settings_obj.anthropic_api_key)
        openai_active = bool(env_openai_key) or bool(settings_obj.openai_api_key)
        if settings_obj.llm_provider == "openai":
            ai_active = openai_active
        else:
            ai_active = claude_active
 
        if request.POST.get("action") == "test":
            result = _test_api_key(settings_obj)
            return _render_settings(request, settings_obj, effective_claude_masked,
                                    effective_openai_masked, claude_active, openai_active,
                                    ai_active, active_subscriptions, expired_subscriptions,
                                    pending_subscriptions, test_result=result)
 
        return _render_settings(request, settings_obj, effective_claude_masked,
                                effective_openai_masked, claude_active, openai_active,
                                ai_active, active_subscriptions, expired_subscriptions,
                                pending_subscriptions, saved=True)
 
    return _render_settings(request, settings_obj, effective_claude_masked,
                            effective_openai_masked, claude_active, openai_active,
                            ai_active, active_subscriptions, expired_subscriptions,
                            pending_subscriptions)
 
 
def _render_settings(request, settings_obj, claude_masked, openai_masked,
                     claude_active, openai_active, ai_active,
                     active_subs, expired_subs, pending_subs,
                     saved=False, test_result=None):
    from django.shortcuts import render
    return render(request, "stores/settings.html", {
        "settings": settings_obj,
        # Claude
        "masked_key_value": claude_masked,
        "claude_active": claude_active,
        # OpenAI
        "openai_masked_key_value": openai_masked,
        "openai_active": openai_active,
        # General
        "ai_active": ai_active,
        "saved": saved,
        "test_result": test_result,
        # Subscriptions
        "active_subscriptions": active_subs,
        "expired_subscriptions": expired_subs,
        "pending_subscriptions": pending_subs,
    })


@staff_member_required
def admin_vendors(request):
    """Admin view — list all registered ACA vendors with stats."""

    status = request.GET.get("status", "")

    # Base queryset
    vendors = Vendor.objects.all()

    if status:
        vendors = vendors.filter(subscription__status=status)

    vendors = vendors.annotate(
        product_count=Count("products"),
        in_stock_count=Count("products", filter=Q(products__in_stock=True))
    )
    vendor_data = [
        {
            "vendor": v,
            "product_count": v.product_count,
            "in_stock_count": v.in_stock_count,
        }
        for v in vendors
    ]

    return render(request, "stores/vendors.html", {
        "vendor_data": vendor_data,
        "total_vendors": Vendor.objects.count(),
        "approved_vendors": Vendor.objects.filter(is_approved=True).count(),
        "filter_total": vendors.count(),
        "status": status,
    })

@staff_member_required
@require_POST
def admin_toggle_vendor(request, vendor_id):
    """Admin: approve or disapprove a vendor."""
    vendor = get_object_or_404(Vendor, id=vendor_id)
    vendor.is_approved = not vendor.is_approved
    vendor.save(update_fields=["is_approved"])
    return redirect("stores:vendors")


@staff_member_required
def admin_vendor_detail(request, vendor_id):
    """Admin view — show a single vendor's info and all their products."""
    vendor = get_object_or_404(Vendor, id=vendor_id)
    products = vendor.products.prefetch_related("images").all()

    return render(request, "stores/vendor_detail.html", {
        "vendor": vendor,
        "products": products,
        "product_count": products.count(),
        "in_stock_count": products.filter(in_stock=True).count(),
    })


def _test_api_key(settings_obj):
    """Quick validation of whichever provider is currently selected."""
    import django.conf as _djconf
 
    provider = settings_obj.llm_provider
 
    if provider == "openai":
        env_key = getattr(_djconf.settings, "OPENAI_API_KEY", "")
        key = env_key or settings_obj.openai_api_key
        if not key:
            return {"success": False, "error": "No OpenAI API key configured"}
        try:
            import openai
            client = openai.OpenAI(api_key=key)
            resp = client.chat.completions.create(
                model=settings_obj.openai_model or "gpt-4o-mini",
                max_tokens=10,
                messages=[{"role": "user", "content": "Say OK"}],
            )
            return {"success": True, "message": f"Connected to OpenAI {settings_obj.openai_model}"}
        except Exception as exc:
            return {"success": False, "error": str(exc)}
 
    else:  # Claude
        env_key = getattr(_djconf.settings, "ANTHROPIC_API_KEY", "")
        key = env_key or settings_obj.anthropic_api_key
        if not key:
            return {"success": False, "error": "No Anthropic API key configured"}
        try:
            import anthropic
            client = anthropic.Anthropic(api_key=key)
            resp = client.messages.create(
                model=settings_obj.llm_model,
                max_tokens=32,
                messages=[{"role": "user", "content": "Say OK"}],
            )
            return {"success": True, "message": f"Connected to Claude {settings_obj.llm_model}"}
        except Exception as exc:
            return {"success": False, "error": str(exc)}


def _ping_store(store):
    url = store.base_api_url.rstrip("/") + "/" + store.search_endpoint.strip("/") + "/"
    headers = {"Accept": "application/json"}
    if store.auth_method == "api_key_header" and store.api_key:
        headers[store.auth_header_name] = store.api_key
    elif store.auth_method == "bearer_token" and store.api_key:
        headers["Authorization"] = f"Bearer {store.api_key}"

    try:
        start = time.monotonic()
        resp = http_requests.get(url, headers=headers, timeout=10)
        elapsed_ms = int((time.monotonic() - start) * 1000)
        StoreHealthLog.objects.create(
            store=store, status_code=resp.status_code,
            response_time_ms=elapsed_ms, success=resp.ok,
        )
        try:
            data = resp.json()
            count = len(data) if isinstance(data, list) else len(data.get("results", data.get("products", [])))
        except Exception:
            count = None
        return {"success": resp.ok, "status_code": resp.status_code, "response_time_ms": elapsed_ms, "product_count": count, "url": url}
    except http_requests.exceptions.Timeout:
        StoreHealthLog.objects.create(store=store, success=False, error_message="Timeout")
        return {"success": False, "error": "Connection timed out", "url": url}
    except http_requests.exceptions.ConnectionError:
        StoreHealthLog.objects.create(store=store, success=False, error_message="Connection refused")
        return {"success": False, "error": "Could not connect to store", "url": url}
    except Exception as exc:
        StoreHealthLog.objects.create(store=store, success=False, error_message=str(exc))
        return {"success": False, "error": str(exc), "url": url}


def _parse_json(value):
    try:
        return json.loads(value) if value and value.strip() else {}
    except (json.JSONDecodeError, AttributeError):
        return {}
