import os

import pytest
import shutil
from flask import Flask, jsonify
from flask_login import LoginManager
from peewee import SqliteDatabase

from app import app as application
from data import model
from data.database import (close_db_filter, db)
from data.model.user import LoginWrappedDBUser
from endpoints.api import api_bp
from initdb import initialize_database, populate_database
from path_converters import APIRepositoryPathConverter, RegexConverter


# TODO(jschorr): Unify with the API conftest once the other PR gets in.

@pytest.fixture()
def app(appconfig):
  """ Used by pytest-flask plugin to inject app by test for client See test_security by name injection of client. """
  app = Flask(__name__)
  login_manager = LoginManager(app)

  @app.errorhandler(model.DataModelException)
  def handle_dme(ex):
    response = jsonify({'message': ex.message})
    response.status_code = 400
    return response

  @login_manager.user_loader
  def load_user(user_uuid):
    return LoginWrappedDBUser(user_uuid)

  app.url_map.converters['regex'] = RegexConverter
  app.url_map.converters['apirepopath'] = APIRepositoryPathConverter
  app.register_blueprint(api_bp, url_prefix='/api')
  app.config.update(appconfig)
  return app


@pytest.fixture(scope="session")
def init_db_path(tmpdir_factory):
  """ Creates a new db and appropriate configuration. Used for parameter by name injection. """
  sqlitedb_file = str(tmpdir_factory.mktemp("data").join("test.db"))
  sqlitedb = 'sqlite:///{0}'.format(sqlitedb_file)
  conf = {"TESTING": True,
          "DEBUG": True,
          "DB_URI": sqlitedb}
  os.environ['TEST_DATABASE_URI'] = str(sqlitedb)
  os.environ['DB_URI'] = str(sqlitedb)
  db.initialize(SqliteDatabase(sqlitedb_file))
  application.config.update(conf)
  application.config.update({"DB_URI": sqlitedb})
  initialize_database()
  populate_database()
  close_db_filter(None)
  return str(sqlitedb_file)


@pytest.fixture()
def database_uri(monkeypatch, init_db_path, sqlitedb_file):
  """ Creates the db uri. Used for parameter by name injection. """
  shutil.copy2(init_db_path, sqlitedb_file)
  db.initialize(SqliteDatabase(sqlitedb_file))
  db_path = 'sqlite:///{0}'.format(sqlitedb_file)
  monkeypatch.setenv("DB_URI", db_path)
  return db_path


@pytest.fixture()
def sqlitedb_file(tmpdir):
  """ Makes file for db. Used for parameter by name injection. """
  test_db_file = tmpdir.mkdir("quaydb").join("test.db")
  return str(test_db_file)


@pytest.fixture()
def appconfig(database_uri):
  """ Makes conf with database_uri. Used for parameter by name injection """
  conf = {
    "TESTING": True,
    "DEBUG": True,
    "DB_URI": database_uri,
    "SECRET_KEY": 'superdupersecret!!!1',
  }
  return conf