import logging
import os
import tempfile
import uuid

from flask import jsonify, Response
from flask_restful import Resource

from blackant.utils.logging import get_logger
from task.task import Task
from task.dao import TaskDao
from task.errors import TaskDoesNotExistsError
from task.log_adapter import TaskIdAdapter
from task.parsers.request import RequestParser


class TaskResource(Resource):
    def __init__(self):
        self.__task_dao = TaskDao.get_instance()

    def get(self, task_id=None):
        if task_id is not None:
            try:
                task = self.__task_dao.get_task(task_id)
                response = jsonify(task.response)
            except TaskDoesNotExistsError:
                response = Response(status=404)
        else:
            response = jsonify(self.__task_dao.get_task_ids())
        return response

    def post(self):
        configuration = RequestParser().parse(None)
        unique_uuid = uuid.uuid4().hex
        tmp_dir = tempfile.gettempdir()

        log_file_handler = logging.FileHandler(
            os.path.join(tmp_dir, "user_log_{}.log".format(unique_uuid)), mode="w"
        )
        log_file_handler.setLevel(logging.DEBUG)

        calculation_logger_instance = get_logger("calculation_{}".format(unique_uuid))
        calculation_logger_instance.setLevel(logging.DEBUG)
        calculation_logger_instance.addHandler(log_file_handler)
        calculation_logger = TaskIdAdapter(calculation_logger_instance, {})

        task_logger_instance = get_logger("task_{}".format(unique_uuid))
        task_logger_instance.setLevel(logging.DEBUG)
        task_logger_instance.addHandler(log_file_handler)
        task_logger = TaskIdAdapter(task_logger_instance, {})

        cmd_args = configuration.cmd_args if configuration.cmd_args else {}
        try:
            # Dynamic calculation loading using CalculationLoader
            # Supports environment variable configuration (CALCULATION_MODULE, CALCULATION_CLASS)
            from calculation.loader import CalculationLoader  # pylint: disable=import-outside-toplevel

            loader = CalculationLoader()
            CalculationClass = loader.get_calculation()
            calculation = CalculationClass(calculation_logger, **cmd_args)
        # The too-broad exception warning is suppressed because we want to handle exceptions
        except Exception:  # pylint: disable=broad-except
            task_logger.exception("Cannot create the calculation instance.")
            calculation = None
        new_task = Task(calculation, configuration, log_file_handler, task_logger)

        new_task_id = self.__task_dao.add_task(new_task)
        task_logger.info("The calculated task UUID: {}".format(new_task_id))
        calculation_logger.set_task_id(new_task_id)
        task_logger.set_task_id(new_task_id)

        new_task.run()

        response = jsonify(new_task_id)
        return response

    def delete(self, task_id):
        try:
            task = self.__task_dao.get_task(task_id)
            task.stop()
            response = jsonify(self.__task_dao.delete_task(task_id))
        except TaskDoesNotExistsError:
            response = Response(status=404)
        return response
