"""Deleting a tenant takes its per-field indexes with it, and new records get
time-ordered ids (see the storage notes in app/crud/field_indexes.py)."""

import importlib.util
import uuid
from pathlib import Path

from sqlalchemy import text

from app.crud import entity_storage, field_indexes
from tests.conftest import AsyncSessionLocal

_spec = importlib.util.spec_from_file_location("drop_orphaned_field_indexes", Path(__file__).parent.parent / "scripts" / "drop_orphaned_field_indexes.py")
cleanup = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(cleanup)


async def _indexes_of(kind: str, source_id: str) -> list[str]:
    async with AsyncSessionLocal() as db:
        return list(await field_indexes.existing_indexes(db, kind, uuid.UUID(source_id)))


async def test_deleting_a_tenant_takes_its_field_indexes(client, auth_headers, test_tenant):
    master = await client.post("/masters", headers=auth_headers, json={"name": f"Indexed {uuid.uuid4().hex[:6]}", "field_schema": [{"name": "code", "type": "varchar", "indexed": True}]})
    assert master.status_code == 201, master.text
    form = await client.post("/forms", headers=auth_headers, json={"name": f"Indexed {uuid.uuid4().hex[:6]}", "field_definitions": [{"name": "ref", "type": "text", "label": "Ref", "indexed": True}]})
    assert form.status_code == 201, form.text
    master_id, form_id = master.json()["id"], form.json()["form_id"]
    await field_indexes.wait_for_pending()
    assert len(await _indexes_of("master", master_id)) == 1
    assert len(await _indexes_of("form", form_id)) == 1

    async with AsyncSessionLocal() as db, db.begin():
        await entity_storage.drop_tenant_storage(db, test_tenant["tenant_id"])

    # The job has to outlive the tenant it was for.
    async with AsyncSessionLocal() as db:
        tenants = (await db.execute(text("SELECT tenant_id FROM jobs WHERE dedupe_key = :k AND status = 'queued'"), {"k": f"{field_indexes.JOB_KIND}:master:{master_id}"})).scalars().all()
    assert tenants == [None]

    await field_indexes.wait_for_pending()
    assert await _indexes_of("master", master_id) == []
    assert await _indexes_of("form", form_id) == []


async def test_another_tenants_indexes_are_left_alone(client, auth_headers, test_tenant):
    master = await client.post("/masters", headers=auth_headers, json={"name": f"Indexed {uuid.uuid4().hex[:6]}", "field_schema": [{"name": "code", "type": "varchar", "indexed": True}]})
    master_id = master.json()["id"]
    await field_indexes.wait_for_pending()
    async with AsyncSessionLocal() as db, db.begin():
        await entity_storage.drop_tenant_storage(db, uuid.uuid4())
    await field_indexes.wait_for_pending()
    assert len(await _indexes_of("master", master_id)) == 1


def test_cleanup_only_picks_field_indexes_with_no_source():
    live, gone = uuid.uuid4().hex, uuid.uuid4().hex
    names = [f"ix_ff_m_{live}_abc123", f"ix_ff_f_{gone}_abc123", "idx_master_records_master", f"ix_ff_other_{gone}"]
    assert cleanup.orphaned(names, {live}) == [f"ix_ff_f_{gone}_abc123"]


async def test_new_records_get_time_ordered_ids(client, auth_headers):
    master = await client.post("/masters", headers=auth_headers, json={"name": f"Ids {uuid.uuid4().hex[:6]}", "field_schema": [{"name": "title", "type": "varchar"}]})
    master_id = master.json()["id"]
    ids = []
    for _ in range(3):
        made = await client.post(f"/masters/{master_id}/records", headers=auth_headers, json={"field_values": {"title": "x"}})
        assert made.status_code == 201, made.text
        ids.append(made.json()["id"])
    assert {uuid.UUID(i).version for i in ids} == {7}

    form = await client.post("/forms", headers=auth_headers, json={"name": f"Ids {uuid.uuid4().hex[:6]}", "field_definitions": [{"name": "subject", "type": "text", "label": "Subject"}]})
    published = (await client.post(f"/forms/{form.json()['form_id']}/publish", headers=auth_headers)).json()
    made = await client.post("/form-submissions", headers=auth_headers, json={"form_id": published["form_id"], "form_version": published["version"], "field_values": {"subject": "x"}})
    assert uuid.UUID(made.json()["id"]).version == 7
