import json
import logging

from app_be.services.dropboxservice import DropboxService
from app_be.services.hashservice import create_sha512
from app_be.services.minioservice import MinioService
from app_be.services.mongodbservice import MongoDBService
from app_be.services.wrapperservice import WrapperService
from django.http import HttpRequest
from django.http import JsonResponse
from rest_framework.decorators import api_view

logger = logging.getLogger(__name__)


class TestApiClass:
    @staticmethod
    @api_view(['GET'])
    def test_api(request):
        logger.debug('Test api call: {}'.format(request))
        return JsonResponse({'Result': 'success'}, safe=False)


class ImageEndpoint:
    @staticmethod
    @api_view(['GET'])
    def image_api_get_all(request):
        logger.debug('Image GET all call: {}'.format(request))
        print(request)

        metadata = MongoDBService.getAll()
        print(metadata)

        return JsonResponse({'Result': 'success1'}, safe=False)

    @staticmethod
    @api_view(['GET'])
    def image_api_get_single(request, identifier):
        logger.debug('Image GET single call: {}'.format(request))

        # get metadata from MongoDB
        metadata = MongoDBService.getSingle(identifier)
        if not metadata:
            return JsonResponse({'Result': 'Error - could not find any metadata in mongoDB.',
                                 'id': identifier}, status=404, safe=False)
        logger.debug('Mongo Meta: {}'.format(metadata))

        # get stored SHA512 hash
        stored_hash = metadata.get('sha512', '')
        logger.debug('Sorted SHA512: {}'.format(stored_hash))

        # get image bytes from Dropbox
        dropbox_image_bytes = DropboxService.read_file(metadata['filename'])
        if dropbox_image_bytes is None:
            return JsonResponse({'Result': 'Error - could not find image in dropbox.', 'id': identifier}, status=404,
                                safe=False)

        # calc dropbox image hash
        actual_dropbox_hash = create_sha512(dropbox_image_bytes)
        logger.debug('Actual Dropbox SHA512: {}'.format(actual_dropbox_hash))
        if stored_hash != actual_dropbox_hash:
            return JsonResponse('Stored hash does not match generated one! '
                                'stored: {} actual: {}'.format(stored_hash, actual_dropbox_hash), safe=False)

        # get image bytes from MinIO
        minio_image_bytes = MinioService.read_file(metadata['filename'])
        if minio_image_bytes is None:
            return JsonResponse({'Result': 'Error - could not find image in minIO.', 'id': identifier}, status=404,
                                safe=False)

        # calc minIO image hash
        actual_minio_hash = create_sha512(minio_image_bytes)
        logger.debug('Actual MinIO SHA512: {}'.format(actual_minio_hash))
        if stored_hash != actual_minio_hash:
            return JsonResponse('Stored hash does not match generated one! '
                                'stored: {} actual: {}'.format(stored_hash, actual_minio_hash), status=404, safe=False)

        payload = {
            'id': identifier,
            'metadata': metadata,
            'image_data': WrapperService.wrap_file(dropbox_image_bytes)
        }

        return JsonResponse(payload, safe=False)

    @staticmethod
    @api_view(['POST'])
    def image_api_post(request: HttpRequest):
        logger.debug('Image POST call: {}'.format(request))
        payload = json.loads(request.body)
        b64encoded_image = payload['image_data']
        identifier = payload['id']
        metadata = payload['metadata']
        filename = payload['metadata']['filename']

        decoded_image = WrapperService.unwrap_file(b64encoded_image)

        MongoDBService.createSingle(metadata, identifier, decoded_image)

        if not DropboxService.create_file(filename, decoded_image):
            print("Could not save image to dropbox")
        if not MinioService.create_file(filename, decoded_image):
            print("Could not save image to minio")
        return JsonResponse({'id': identifier, 'filename': filename},
                            safe=False)  # 'metadata': metadata response beinhaltet ObjectId welche nicht serializable is?

    @staticmethod
    @api_view(['DELETE'])
    def image_api_delete(request: HttpRequest, identifier):

        logger.debug('Image DELETE single call: {}'.format(request))
        result_bool = True

        # get metadata from MongoDB
        metadata = MongoDBService.getSingle(identifier)

        if not metadata:
            return JsonResponse({'Result': 'Error - could not find any metadata in mongoDB.',
                                 'id': identifier}, status=404, safe=False)

        resp = MongoDBService.deleteSingle(identifier)
        print(resp)


        if not DropboxService.delete_file(metadata['filename']):
            print('Error deleting file in dropbox')
            result_bool = False

        if not MinioService.delete_file(metadata['filename']):
            print('Error deleting file in minio')
            result_bool = False

        return JsonResponse({'Result': result_bool}, safe=False)

    @staticmethod
    @api_view(['DELETE'])
    def image_api_delete_all(request: HttpRequest):

        logger.debug('Image DELETE single call: {}'.format(request))
        result_bool = True

        resp = MongoDBService.deleteAll()
        print(resp)

        if not DropboxService.delete_all():
            print('Error deleting dropbox folder')
            result_bool = False

        return JsonResponse({'Result': result_bool}, safe=False)

    @staticmethod
    @api_view(['PUT'])
    def image_api_update(request, identifier):

        logger.debug('Image UPDATE single call: {}'.format(request))

        # get metadata from MongoDB
        metadata = MongoDBService.getSingle(identifier)
        if not metadata:
            return JsonResponse({'Result': 'Error - Could not find image to be updated',
                                 'id': identifier}, status=404, safe=False)

        DropboxService.delete_file(metadata['filename'])
        # MinioService.delete_file(metadata['filename'])
        MongoDBService.deleteSingle(identifier)


        payload = json.loads(request.body)
        b64encoded_image = payload['image_data']
        identifier = payload['id']
        metadata = payload['metadata']
        filename = payload['metadata']['filename']

        decoded_image = WrapperService.unwrap_file(b64encoded_image)

        MongoDBService.createSingle(metadata, identifier, decoded_image)

        if not DropboxService.create_file(filename, decoded_image):
            print("Could not save image to dropbox")
        if not MinioService.create_file(filename, decoded_image):
            print("Could not save image to minio")
        return JsonResponse({'id': identifier, 'filename': filename},
                            safe=False)

class HealthEndpoint:
    @staticmethod
    @api_view(['GET'])
    def check_systems(request):
        logger.debug('Check health of all sub-systems')
        mongo = MongoDBService.check()
        dbx = DropboxService.check()
        minio = MinioService.check()

        return JsonResponse({'MongoDB': mongo, 'Dropbox': dbx, 'MinIO': minio}, safe=False)
