"""
NordaBiz Test Configuration and Fixtures
=========================================

Shared fixtures for all test types:
- app: Flask application instance
- client: Test client for HTTP requests
- auth_client: Client with logged-in regular user session
- admin_client: Client with logged-in admin session
- db_session: Database session for integration tests
"""

import os
import sys
from pathlib import Path

import pytest

# Add project root to path for imports
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT))

# Set testing environment before importing app
os.environ['FLASK_ENV'] = 'testing'
os.environ['TESTING'] = 'true'

# If no DATABASE_URL, use SQLite for tests
if not os.environ.get('DATABASE_URL'):
    os.environ['DATABASE_URL'] = 'sqlite:///:memory:'


# =============================================================================
# Database Availability Check
# =============================================================================

def is_database_available():
    """Check if database is available for testing."""
    try:
        from database import engine
        with engine.connect() as conn:
            pass
        return True
    except Exception:
        return False


# =============================================================================
# Flask Application Fixtures
# =============================================================================

@pytest.fixture(scope='session')
def app():
    """Create Flask application for testing."""
    from app import app as flask_app

    flask_app.config.update({
        'TESTING': True,
        'WTF_CSRF_ENABLED': False,  # Disable CSRF for tests
        'LOGIN_DISABLED': False,
        'SERVER_NAME': 'localhost',
        'SESSION_COOKIE_SECURE': False,
        'SESSION_COOKIE_HTTPONLY': True,
    })

    with flask_app.app_context():
        yield flask_app


@pytest.fixture
def client(app):
    """Create test client for HTTP requests."""
    return app.test_client()


@pytest.fixture
def runner(app):
    """Create CLI runner for testing CLI commands."""
    return app.test_cli_runner()


# =============================================================================
# Authentication Fixtures
# =============================================================================

# Test credentials (from CLAUDE.md)
TEST_USER_EMAIL = 'test@nordabiznes.pl'
TEST_USER_PASSWORD = '&Rc2LdbSw&jiGR0ek@Bz'
TEST_ADMIN_EMAIL = 'testadmin@nordabiznes.pl'
TEST_ADMIN_PASSWORD = 'cSfQbbwegwv1v3Q2Dm0Q'


def _scrypt_available():
    """Check if hashlib.scrypt is available (required for password verification)."""
    try:
        import hashlib
        hashlib.scrypt(b'test', salt=b'salt', n=2, r=1, p=1)
        return True
    except (AttributeError, ValueError):
        return False


SCRYPT_AVAILABLE = _scrypt_available()


@pytest.fixture
def auth_client(client, app):
    """
    Create test client with logged-in regular user session.

    Uses test account: test@nordabiznes.pl
    Role: MEMBER (regular user)
    """
    if not SCRYPT_AVAILABLE:
        pytest.skip("hashlib.scrypt not available - cannot test login")

    with app.app_context():
        response = client.post('/login', data={
            'email': TEST_USER_EMAIL,
            'password': TEST_USER_PASSWORD,
        }, follow_redirects=True)

        # Check if login succeeded by verifying we're not redirected back to login
        if '/login' in response.request.path:
            pytest.skip("Login failed - check test user credentials or database")

        return client


@pytest.fixture
def admin_client(client, app):
    """
    Create test client with logged-in admin session.

    Uses test account: testadmin@nordabiznes.pl
    Role: ADMIN
    """
    if not SCRYPT_AVAILABLE:
        pytest.skip("hashlib.scrypt not available - cannot test login")

    with app.app_context():
        response = client.post('/login', data={
            'email': TEST_ADMIN_EMAIL,
            'password': TEST_ADMIN_PASSWORD,
        }, follow_redirects=True)

        # Check if login succeeded
        if '/login' in response.request.path:
            pytest.skip("Admin login failed - check test admin credentials or database")

        return client


# =============================================================================
# Database Fixtures
# =============================================================================

class DatabaseWrapper:
    """Wrapper for database access in tests."""

    def __init__(self):
        from database import engine, SessionLocal
        self.engine = engine
        self.SessionLocal = SessionLocal
        self._session = None

    @property
    def session(self):
        if self._session is None:
            self._session = self.SessionLocal()
        return self._session

    def close(self):
        if self._session:
            self._session.close()
            self._session = None


@pytest.fixture(scope='session')
def db(app):
    """Get database wrapper instance."""
    wrapper = DatabaseWrapper()
    yield wrapper
    wrapper.close()


@pytest.fixture
def db_session(db, app):
    """
    Create database session for integration tests.

    Rolls back changes after each test.
    """
    with app.app_context():
        session = db.SessionLocal()
        yield session
        session.rollback()
        session.close()


# =============================================================================
# Mock Fixtures
# =============================================================================

@pytest.fixture
def mock_gemini(mocker):
    """Mock Gemini AI service for unit tests."""
    mock = mocker.patch('gemini_service.generate_content')
    mock.return_value = {
        'text': 'Mocked AI response for testing',
        'companies': []
    }
    return mock


@pytest.fixture
def mock_email(mocker):
    """Mock email sending for tests."""
    return mocker.patch('flask_mail.Mail.send')


# =============================================================================
# Test Data Fixtures
# =============================================================================

@pytest.fixture
def sample_company():
    """Sample company data for tests."""
    return {
        'name': 'Test Company Sp. z o.o.',
        'slug': 'test-company-sp-z-o-o',
        'nip': '1234567890',
        'category': 'IT',
        'short_description': 'Test company for automated tests',
        'website': 'https://test-company.pl',
        'email': 'contact@test-company.pl',
        'phone': '+48 123 456 789',
    }


@pytest.fixture
def sample_user():
    """Sample user data for tests."""
    return {
        'email': 'newuser@test.pl',
        'password': 'SecurePassword123!',
        'first_name': 'Test',
        'last_name': 'User',
    }


# =============================================================================
# URL Fixtures
# =============================================================================

@pytest.fixture
def production_url():
    """Production URL for smoke tests."""
    return 'https://nordabiznes.pl'


@pytest.fixture
def staging_url():
    """Staging URL for E2E tests."""
    return 'https://staging.nordabiznes.pl'


# =============================================================================
# Cleanup Fixtures
# =============================================================================

@pytest.fixture(autouse=True)
def cleanup_after_test():
    """Cleanup after each test."""
    yield
    # Add any cleanup logic here if needed


# =============================================================================
# Markers Configuration
# =============================================================================

def pytest_configure(config):
    """Configure pytest markers."""
    config.addinivalue_line("markers", "unit: Unit tests")
    config.addinivalue_line("markers", "integration: Integration tests")
    config.addinivalue_line("markers", "e2e: End-to-end tests")
    config.addinivalue_line("markers", "smoke: Smoke tests")
    config.addinivalue_line("markers", "security: Security tests")
    config.addinivalue_line("markers", "migration: Migration tests")
    config.addinivalue_line("markers", "dr: Disaster recovery tests")
    config.addinivalue_line("markers", "slow: Slow tests")
