"""Shared fixtures for bitable unit tests.

Provides:
- ``bitable_db``: initialized BitableDB (skips if PG unavailable)
- ``bitable_service``: BitableService backed by bitable_db
- Factory functions: make_table, make_field, make_record, make_formula_field
"""

from __future__ import annotations

import os

import pytest

from agentkit.bitable.models import FieldOwner, FieldType


def _pg_available() -> bool:
    """Check if PostgreSQL is reachable via DATABASE_URL env var."""
    url = os.environ.get("DATABASE_URL") or os.environ.get("AGENTKIT_DATABASE_URL")
    return bool(url)


@pytest.fixture
async def bitable_db():
    """Initialize a fresh bitable DB for each test (skips if PG unavailable)."""
    if not _pg_available():
        pytest.skip("PostgreSQL not available (set DATABASE_URL)")

    from agentkit.bitable.db import BitableDB

    db = BitableDB()
    try:
        await db.init()
        # Clean slate: drop and recreate bitable schema
        from sqlalchemy import text

        async with db.engine.begin() as conn:
            await conn.execute(text("DROP SCHEMA IF EXISTS bitable CASCADE"))
        await db.init()  # re-create fresh
        yield db
    finally:
        # Cleanup
        from sqlalchemy import text

        if db.engine is not None:
            async with db.engine.begin() as conn:
                await conn.execute(text("DROP SCHEMA IF EXISTS bitable CASCADE"))
        await db.close()


@pytest.fixture
async def bitable_service(bitable_db):
    """BitableService backed by the test bitable_db."""
    from agentkit.bitable.service import BitableService

    yield BitableService(bitable_db)


# ── Factory fixtures ───────────────────────────────────────


@pytest.fixture
def make_table(bitable_service):
    """Factory: create a table and return it."""

    counter = [0]

    async def _make(
        name: str | None = None,
        description: str = "",
        primary_key_field_id: str | None = None,
    ):
        counter[0] += 1
        return await bitable_service.create_table(
            name=name or f"test_table_{counter[0]}",
            description=description,
            primary_key_field_id=primary_key_field_id,
        )

    return _make


@pytest.fixture
def make_field(bitable_service):
    """Factory: create a field and return it."""

    counter = [0]

    async def _make(
        table_id: str,
        name: str | None = None,
        field_type: FieldType = FieldType.text,
        config: dict | None = None,
        owner: FieldOwner = FieldOwner.agent,
    ):
        counter[0] += 1
        return await bitable_service.create_field(
            table_id=table_id,
            name=name or f"field_{counter[0]}",
            field_type=field_type,
            config=config or {},
            owner=owner,
        )

    return _make


@pytest.fixture
def make_record(bitable_service):
    """Factory: create a record and return it."""
    counter = [0]

    async def _make(table_id: str, values: dict | None = None):
        counter[0] += 1
        return await bitable_service.create_record(
            table_id=table_id,
            values=values or {},
        )

    return _make


@pytest.fixture
def make_formula_field(bitable_service):
    """Factory: create a formula field and return it."""
    counter = [0]

    async def _make(
        table_id: str,
        name: str | None = None,
        formula_expr: str = "=1+1",
    ):
        counter[0] += 1
        return await bitable_service.create_field(
            table_id=table_id,
            name=name or f"calc_{counter[0]}",
            field_type=FieldType.formula,
            config={"formula_expr": formula_expr},
            owner=FieldOwner.user,
        )

    return _make
