import pytest
import pytest_asyncio
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from starlette.testclient import TestClient
from sqlalchemy import select
from src.database import get_db, Base
from src.customer.models import Customer
from src.main import app

DATABASE_URL = "sqlite+aiosqlite:///:memory:"

engine = create_async_engine(DATABASE_URL, future=True, echo=False)
AsyncSessionLocal = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)

@pytest_asyncio.fixture(scope="session", autouse=True)
async def prepare_database():
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)

@pytest_asyncio.fixture()
async def db_session():
    async with AsyncSessionLocal() as session:
        yield session
        await session.rollback()

@pytest.fixture()
def client(db_session):
    def override_get_db():
        yield db_session

    app.dependency_overrides[get_db] = override_get_db

    with TestClient(app) as client:
        yield client

    app.dependency_overrides.clear()

@pytest.mark.asyncio
async def test_create_customer_success(client):
    payload = {
        "name": "Test User",
        "phone": "+380501112233",
        "password": "password123",
        "comment": "Test comment"
    }
    response = client.post("/customer", data=payload)
    assert response.status_code == 200
    json_data = response.json()
    assert json_data["status"] is True
    assert json_data["data"]["name"] == "Test User"
    assert json_data["data"]["phone"].endswith("1112233")
    assert json_data["data"]["comment"] == "Test comment"

@pytest.mark.asyncio
async def test_create_customer_missing_required(client):
    payload = {
        "phone": "+380501112233",
        # пропущено name і password
    }
    response = client.post("/customer", data=payload)
    assert response.status_code == 422

@pytest.mark.asyncio
async def test_get_customer_by_id_success(client, db_session):
    # Спершу створюємо користувача безпосередньо через сесію
    customer = Customer(
        name="Existing User",
        phone="380501234567",
        password="hashed_password",
        comment="exist comment",
        auth_type="phone",
        banned=False
    )
    db_session.add(customer)
    await db_session.commit()
    await db_session.refresh(customer)

    response = client.get(f"/customer/{customer.customer_id}")
    assert response.status_code == 200
    data = response.json()
    assert data["status"] is True
    assert data["data"]["customer_id"] == customer.customer_id
    assert data["data"]["name"] == "Existing User"

@pytest.mark.asyncio
async def test_get_customer_by_id_not_found(client):
    response = client.get("/customer/999999")
    assert response.status_code == 200
    data = response.json()
    assert data["status"] is False

@pytest.mark.asyncio
async def test_update_customer_success(client, db_session):
    customer = Customer(
        name="User To Update",
        phone="380501234560",
        password="old_hashed",
        comment="old comment",
        auth_type="phone",
        banned=False
    )
    db_session.add(customer)
    await db_session.commit()
    await db_session.refresh(customer)

    payload = {
        "name": "Updated User",
        "comment": "Updated comment",
        "banned": True
    }

    response = client.patch(f"/customer/{customer.customer_id}", data=payload)
    assert response.status_code == 200
    data = response.json()
    assert data["status"] is True
    assert data["data"]["name"] == "Updated User"
    assert data["data"]["comment"] == "Updated comment"
    assert data["data"]["banned"] is True

@pytest.mark.asyncio
async def test_delete_customer_success(client, db_session):
    customer = Customer(
        name="User To Delete",
        phone="380501234569",
        password="pass",
        comment=None,
        auth_type="phone",
        banned=False
    )
    db_session.add(customer)
    await db_session.commit()
    await db_session.refresh(customer)

    response = client.delete(f"/customer/{customer.customer_id}")
    assert response.status_code == 200
    data = response.json()
    assert data["status"] is True

    result = await db_session.execute(
        select(Customer).where(Customer.customer_id == customer.customer_id)
    )
    deleted = result.scalar_one_or_none()
    assert deleted is None

@pytest.mark.asyncio
async def test_delete_customer_not_found(client):
    response = client.delete("/customer/999999")
    assert response.status_code == 200
    data = response.json()
    assert data["status"] is False
