import os
import sys

# SQLite in-memory for tests — no PostgreSQL needed
os.environ.setdefault("DATABASE_URL", "sqlite:///./test.db")
os.environ.setdefault("SIGNING_KEY", "test-signing-key-32chars-padding!!")
os.environ.setdefault("ADMIN_USERNAME", "admin")
os.environ.setdefault("ADMIN_PASSWORD", "testpass123")
os.environ.setdefault("PUBLIC_HOST", "http://localhost")
os.environ.setdefault("ENABLE_STARTUP_MAINTENANCE", "0")
os.environ.setdefault("LOG_LEVEL", "ERROR")

import pytest
from unittest.mock import MagicMock, patch
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

# Patch docker before importing app modules
_docker_mock = MagicMock()
_docker_mock.containers.get.side_effect = Exception("no docker in tests")
_docker_mock.containers.list.return_value = []
_docker_mock.containers.run.return_value = MagicMock(id="test-container-id", status="running", name="test")

sys.modules.setdefault("docker", MagicMock())

with patch("docker.from_env", return_value=_docker_mock):
    with patch("runtime.ensure_schema_compatibility", lambda: None):
        from database import Base, get_db
        import main as app_module

engine = create_engine(
    "sqlite:///./test.db",
    connect_args={"check_same_thread": False},
    poolclass=StaticPool,
)
TestingSessionLocal = sessionmaker(bind=engine)
Base.metadata.create_all(bind=engine)

# Create admin user
from auth import hash_password
from models import User
with TestingSessionLocal() as db:
    if not db.query(User).filter(User.username == "admin").first():
        import datetime as _dt
        db.add(User(
            username="admin",
            password_hash=hash_password("testpass123"),
            is_admin=True,
            active=True,
            expires_at=_dt.datetime(2099, 1, 1, tzinfo=_dt.timezone.utc),
        ))
        db.commit()


def override_get_db():
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()


app_module.app.dependency_overrides[get_db] = override_get_db


@pytest.fixture(scope="session")
def client():
    with patch("runtime.docker_client", return_value=_docker_mock), \
         patch("runtime.ensure_schema_compatibility", lambda: None):
        with TestClient(app_module.app, raise_server_exceptions=False, base_url="https://testserver") as c:
            yield c


def _extract_csrf(client) -> str:
    """GET / → берём CSRF из HTML и ставим куку вручную."""
    import re
    r = client.get("/", follow_redirects=True)
    assert r.status_code == 200
    m = re.search(r'name=["\']csrf_token["\'][^>]*value=["\']([^"\']+)["\']'
                  r'|value=["\']([^"\']+)["\'][^>]*name=["\']csrf_token["\']', r.text)
    if not m:
        m = re.search(r'csrf_token["\']?\s*[=:]\s*["\']([^"\']{10,})["\']', r.text)
    assert m, f"csrf_token not found in HTML: {r.text[:500]}"
    csrf = m.group(1) or m.group(2)
    client.cookies.set("portal_csrf", csrf, domain="testserver")
    return csrf


@pytest.fixture(scope="session")
def auth_client(client):
    """Client with admin session cookie."""
    csrf = _extract_csrf(client)
    r = client.post("/login", data={
        "username": "admin",
        "password": "testpass123",
        "csrf_token": csrf,
    }, follow_redirects=True)
    assert r.status_code == 200, f"login failed: {r.status_code} {r.text[:300]}"
    return client
