"""Test script to verify xapian_model flow against a running Xapiand server.

Requires Xapiand running on localhost:8880.

Prints the JSON body sent in each request to Xapiand.
"""
from __future__ import annotations

import asyncio
import json

import xapiand
from xapiand import Xapiand
from xapian_model import base as xm_base
from xapian_model.base import BaseXapianModel

# Use commit=True so documents are immediately visible; force JSON for readability
_client = Xapiand(commit=True, default_accept="application/json")
xapiand.client = _client
xm_base.client = _client

# Monkey-patch _send_request to print request details
_original_send = Xapiand._send_request

async def _debug_send(self, action_request, index, *, body=None, **kwargs):
    method = self._methods[action_request][0]
    url = self._build_url(action_request, index,
        kwargs.get('host'), kwargs.get('port'),
        kwargs.get('nodename'), kwargs.get('id'))

    # Show the body as it will be sent (with _schema processing applied)
    display_body = body
    if isinstance(body, dict) and '_schema' in body:
        display_body = body.copy()
        schema = display_body['_schema']
        if isinstance(schema, dict):
            schema = schema.copy()
            schema['_foreign'] = f"{self.prefix}{schema['_foreign'].strip('/')}"
            display_body['_schema'] = schema
        else:
            display_body['_schema'] = f"{self.prefix}{schema.strip('/')}"

    print(f"\n  --> {method} {url}")
    if kwargs.get('params'):
        print(f"      params: {json.dumps(kwargs['params'], indent=None)}")
    if display_body is not None:
        print(f"      body:   {json.dumps(display_body, indent=2, default=str)}")
    else:
        print(f"      body:   (none)")

    result = await _original_send(self, action_request, index, body=body, **kwargs)

    print(f"  <-- response: {json.dumps(dict(result) if hasattr(result, 'items') else result, indent=2, default=str)}")
    return result

Xapiand._send_request = _debug_send


class Product(BaseXapianModel):
    INDEX_TEMPLATE = "/demo2_products/{category}"
    SCHEMA = {
        "_type": "foreign/object",
        "_foreign": "/demo2_schemas/product",
        "name": {"_type": "text"},
        "price": {"_type": "float"},
        "tags": {"_type": "keyword"},
    }


async def main():
    # -- 1. Create ---------------------------------------------------------
    print("=" * 60)
    print("1. CREATE")
    print("=" * 60)
    product = await Product.objects.create(
        category="electronics",
        id="phone-1",
        name="Smartphone X",
        price=599.99,
        tags="mobile",
    )

    # -- 2. Get by ID ------------------------------------------------------
    print("\n" + "=" * 60)
    print("2. GET by ID")
    print("=" * 60)
    fetched = await Product.objects.get(id="phone-1", category="electronics", volatile=True)

    # -- 3. Search ---------------------------------------------------------
    print("\n" + "=" * 60)
    print("3. SEARCH")
    print("=" * 60)
    results = await Product.objects.filter(category="electronics", query="Smartphone")

    # -- 4. Update via save() ----------------------------------------------
    print("\n" + "=" * 60)
    print("4. SAVE (update)")
    print("=" * 60)
    fetched.price = 499.99
    await fetched.save()

    # -- 5. Delete ---------------------------------------------------------
    print("\n" + "=" * 60)
    print("5. DELETE")
    print("=" * 60)
    refetched = await Product.objects.get(id="phone-1", category="electronics", volatile=True)
    await refetched.delete()

    # -- Cleanup -----------------------------------------------------------
    for path in ("demo2_schemas/", "demo2_products/"):
        try:
            await _client.session.request(
                "DELETE",
                f"http://127.0.0.1:8880/{_client.prefix}{path}",
                headers={"accept": "application/json"},
            )
        except Exception:
            pass

    print("\n" + "=" * 60)
    print("Done!")


if __name__ == "__main__":
    asyncio.run(main())
