import time
from pathlib import Path

import pytest
import requests

from sqlalchemy import create_engine
from requests.exceptions import ConnectionError
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import sessionmaker, clear_mappers

from src.articles import config
from src.articles.adapters.orm import metadata, start_mappers


@pytest.fixture
def in_memory_db():
    engine = create_engine('sqlite:///:memory:')
    metadata.create_all(engine)
    yield engine


@pytest.fixture
def session_factory(in_memory_db):
    start_mappers()
    yield sessionmaker(bind=in_memory_db)
    clear_mappers()


@pytest.fixture
def session(session_factory):
    yield session_factory()


def wait_for_postgres_to_come_up(engine):
    deadline = time.time() + 10
    while time.time() < deadline:
        try:
            return engine.connect()
        except OperationalError:
            time.sleep(0.5)
    pytest.fail('Postgres never came up')


def wait_for_webapp_to_come_up():
    deadline = time.time() + 10
    url = config.get_api_url()
    while time.time() < deadline:
        try:
            return requests.get(url)
        except ConnectionError:
            time.sleep(0.5)
    pytest.fail('API never came up')


@pytest.fixture(scope='session')
def postgres_db():
    engine = create_engine(config.get_postgres_uri())
    wait_for_postgres_to_come_up(engine)
    metadata.create_all(engine)
    return engine


@pytest.fixture
def postgres_session(postgres_db):
    start_mappers()
    session = sessionmaker(bind=postgres_db)()
    clear_postgres_article_tags(session)
    clear_postgres_articles(session)
    clear_postgres_tags(session)
    clear_postgres_credentials(session)
    yield session
    clear_postgres_articles(session)
    clear_postgres_tags(session)
    clear_postgres_credentials(session)
    clear_mappers()


def clear_postgres_tags(postgres_session):
    postgres_session.execute(
        'DELETE FROM tags'
    )
    postgres_session.commit()


def clear_postgres_articles(postgres_session):
    postgres_session.execute(
        'DELETE FROM articles'
    )
    postgres_session.commit()


def clear_postgres_credentials(postgres_session):
    postgres_session.execute(
        'DELETE FROM credentials'
    )
    postgres_session.commit()


def clear_postgres_article_tags(postgres_session):
    postgres_session.execute(
        'DELETE FROM article_tags'
    )
    postgres_session.commit()


@pytest.fixture
def restart_api():
    (Path(__file__).parent / '../src/articles/entrypoints/web_app.py').touch()
    time.sleep(0.5)
    wait_for_webapp_to_come_up()

import time
from pathlib import Path

import pytest
import requests

from sqlalchemy import create_engine
from requests.exceptions import ConnectionError
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import sessionmaker, clear_mappers

from src.articles import config
from src.articles.adapters.orm import metadata, start_mappers


@pytest.fixture
def in_memory_db():
    engine = create_engine('sqlite:///:memory:')
    metadata.create_all(engine)
    yield engine


@pytest.fixture
def session_factory(in_memory_db):
    start_mappers()
    yield sessionmaker(bind=in_memory_db)
    clear_mappers()


@pytest.fixture
def session(session_factory):
    yield session_factory()


def wait_for_postgres_to_come_up(engine):
    deadline = time.time() + 10
    while time.time() < deadline:
        try:
            return engine.connect()
        except OperationalError:
            time.sleep(0.5)
    pytest.fail('Postgres never came up')


def wait_for_webapp_to_come_up():
    deadline = time.time() + 10
    url = config.get_api_url()
    while time.time() < deadline:
        try:
            return requests.get(url)
        except ConnectionError:
            time.sleep(0.5)
    pytest.fail('API never came up')


@pytest.fixture(scope='session')
def postgres_db():
    engine = create_engine(config.get_postgres_uri())
    wait_for_postgres_to_come_up(engine)
    metadata.create_all(engine)
    return engine


@pytest.fixture
def postgres_session(postgres_db):
    start_mappers()
    session = sessionmaker(bind=postgres_db)()
    clear_postgres_article_tags(session)
    clear_postgres_articles(session)
    clear_postgres_tags(session)
    clear_postgres_credentials(session)
    yield session
    clear_postgres_articles(session)
    clear_postgres_tags(session)
    clear_postgres_credentials(session)
    clear_mappers()


def clear_postgres_tags(postgres_session):
    postgres_session.execute(
        'DELETE FROM tags'
    )
    postgres_session.commit()


def clear_postgres_articles(postgres_session):
    postgres_session.execute(
        'DELETE FROM articles'
    )
    postgres_session.commit()


def clear_postgres_credentials(postgres_session):
    postgres_session.execute(
        'DELETE FROM credentials'
    )
    postgres_session.commit()


def clear_postgres_article_tags(postgres_session):
    postgres_session.execute(
        'DELETE FROM article_tags'
    )
    postgres_session.commit()


@pytest.fixture
def restart_api():
    (Path(__file__).parent / '../src/articles/entrypoints/web_app.py').touch()
    time.sleep(0.5)
    wait_for_webapp_to_come_up()
