import logging
import shutil
import os
from sqlalchemy import engine_from_config
import transaction

from alembic.config import Config
from alembic import command
from pyramid.paster import (
    get_appsettings,
    setup_logging,
)
from ringo.lib.sql import DBSession
from ringo.lib.helpers import get_app_location, dynamic_import
from ringo.lib.imexport import JSONExporter, JSONImporter
from ringo.model.modul import ModulItem

log = logging.getLogger(__name__)


def get_last_revision_file(args):
    """Will return the name of the latest revision file of the application"""
    script_path = []
    script_path.append(get_app_location(args.app))
    script_path.append("alembic")
    script_path.append("versions")
    cwd = os.getcwd()
    os.chdir(os.path.join(*script_path))
    script_path.append(max(os.listdir("."),
                       key=os.path.getctime))
    os.chdir(cwd)
    return os.path.join(*script_path)


def get_session(config_file):
    """Will return a database session based on the application
    configuration"""
    setup_logging(config_file)
    settings = get_appsettings(config_file)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    return DBSession


def copy_initial_migration_scripts(args):
    """Will copy the initial db migration scripts into the alembic
    versions folder of the application.
    """
    dst_path = []
    dst_path.append(get_app_location(args.app))
    dst_path.append("alembic")
    dst_path.append("versions")
    src_path = []
    src_path.append(get_app_location("ringo"))
    src_path.append("alembic")
    src_path.append("versions")

    src = os.path.join(*src_path)
    dst = os.path.join(*dst_path)
    src_files = os.listdir(src)
    # Only copy the initial files if the directory is empty.
    if len(src_files) >= 3:
        return
    for file_name in src_files:
        full_file_name = os.path.join(src, file_name)
        if (os.path.isfile(full_file_name)):
            shutil.copy(full_file_name, dst)


def create_new_revision(args, sql, msg=None):
    """Will create a new autogenerated revision file. Further the
    provided SQL statement will be included in the file."""
    cfg = get_alembic_config(args)
    command.revision(cfg, message=msg, autogenerate=True)
    revision_file = get_last_revision_file(args)
    data = ""
    with open(revision_file, "r") as f:
        data = f.read()
    with open(revision_file, "w") as f:
        f.write(data.replace('INSERTS = """"""',
                             'INSERTS = """%s"""' % "\n".join(sql)))


def get_alembic_config(args, app=None):
    """Return a alembic configuration

    :app: Name of the application
    :returns: Alembic configuration

    """

    config_path = []
    config_path.append(get_app_location(args.app))
    config_path.append("alembic.ini")
    cfg = Config(os.path.join(*config_path))
    if args.config:
        app_config = get_appsettings(args.config)
        cfg.set_main_option("sqlalchemy.url",
                            app_config.get('sqlalchemy.url'))
    return cfg


def handle_db_init_command(args):
    copy_initial_migration_scripts(args)
    handle_db_upgrade_command(args)


def handle_db_upgrade_command(args):
    cfg = get_alembic_config(args)
    command.upgrade(cfg, "head")

def handle_db_savedata_command(args):
    path = []
    path.append(get_app_location(args.app))
    path.append(args.config)
    session = get_session(os.path.join(*path))
    modul_clazzpath = session.query(ModulItem).filter(ModulItem.name == args.modul).all()[0].clazzpath
    modul = dynamic_import(modul_clazzpath)
    exporter = JSONExporter(modul)
    print exporter.perform(session.query(modul).all())

def handle_db_loaddata_command(args):
    path = []
    path.append(get_app_location(args.app))
    path.append(args.config)
    session = get_session(os.path.join(*path))
    modul_clazzpath = session.query(ModulItem).filter(ModulItem.name == args.modul).all()[0].clazzpath
    modul = dynamic_import(modul_clazzpath)
    importer = JSONImporter(modul)
    items = []
    updated = 0
    created = 0
    with open(args.fixture) as f:
        items = importer.perform(f.read())
        for item in [item[0] for item in items]:
            # Add all new items to the session
            if not item.id:
                session.add(item)
                created += 1
            else:
                updated += 1
        try:
            transaction.commit()
            print "Updated %s items, Created %s items" % (updated, created)
        except:
            print "Loading data failed!"

def handle_db_uuid_command(args):
    path = []
    path.append(get_app_location(args.app))
    path.append(args.config)
    session = get_session(os.path.join(*path))
    modul_clazzpath = session.query(ModulItem).filter(ModulItem.name == args.modul).all()[0].clazzpath
    modul = dynamic_import(modul_clazzpath)
    updated = 0
    created = 0
    for item in session.query(modul).all():
        if item.uuid:
            if args.missing_only:
                continue
            else:
                item.reset_uuid()
                updated += 1
        else:
            item.uuid.reset_uuid()
            created += 1
    try:
        transaction.commit()
        print "Updated %s items, Created %s items" % (updated, created)
    except:
        print "Loading data failed!"

