from __future__ import unicode_literals

import copy
import imp

import six

from carry import exc
from carry.dispatcher import TaskDispatcher
from carry.logger import logger
from carry.store import StoreFactory
from carry.task import TaskFactory, TaskClassifier, TableTaskConfig, SQLTaskConfig, PythonTaskConfig
from carry.transform import NoResultFound
from carry.version import __version__

table = TableTaskConfig
sql = SQLTaskConfig
py = PythonTaskConfig


def run(config, task_ids=None):
    try:
        if isinstance(config, six.string_types):
            config = imp.load_source('carry.config', config)
            etl = Carry(config.STORES)
            etl.execute(config.TASKS, task_ids)
        elif isinstance(config, dict):
            config = copy.deepcopy(config)
            etl = Carry(config['STORES'])
            etl.execute(config['TASKS'], task_ids)
    except Exception as e:
        exc.exceptions.add(e)
        raise


class Carry(object):
    def __init__(self, store_configs):
        self.stores = StoreFactory.create_all(store_configs)

    def execute(self, tasks, task_ids):
        task_ids = set(task_ids or ())
        for i, task in enumerate(tasks):
            if task_ids and i not in task_ids:
                continue

            self._execute_task(i, task)
            logger.info('Finish task  {}'.format(i))

        self.stores.drop_created_views()

    def _execute_task(self, num, task):
        sources = task.get('from')
        dest = task.get('to')
        orders = task.get('orders')

        logger.info('Start task {}: Transfer tables from {} to {}'.format(
            num, [source['name'] for source in sources], dest['name'])
        )

        # truncate
        tc = TaskClassifier(orders)
        effected_tables = tc.effected_tables()
        dest_store = self.stores.find_by_store_name(dest['name'])
        dest_store.truncate(effected_tables)

        task_dispatcher = TaskDispatcher(self.stores, task)
        task_dispatcher.dispatch()
