import json
import logging
import os
from tempfile import TemporaryFile

from crypto.models.upload_file import DSResponse_UploadFile
from django.conf import settings
from django.core.files import File
from django.db import transaction
from isc_common.common import SFTP , FILES_STORE_UNKNOWN_TYPE
from isc_common.common.UploadItem import UploadItem
from isc_common.dropzone import Dz
from isc_common.fields.files import make_REPLACE_FILE_PATH
from isc_common.http.DSResponse import JsonResponseWithException
from isc_common.models.image_types import Image_types
from isc_common.models.images import Images
from websocket import create_connection

from lfl_admin.common.management.commands import delete_img_refs

logger = logging.getLogger( __name__ )


class Common_UploadImage( DSResponse_UploadFile ) :
    def upload_image( self , request ) :

        self.dictionary = dict( id=request.GET.get( 'id' ) )

        self.dz_dictionary = Dz( request.POST )

        self.host = request.GET.get( 'host' )
        self.port = request.GET.get( 'port' )
        self.image_type_name = request.GET.get( 'image_type_name' )
        self.keyImage = request.GET.get( 'keyImage' )

        if self.image_type_name is None :
            raise Exception( 'Не задан параметр image_type_name.' )
        if not self.port :
            self.port = 80
        self.channel = request.GET.get( 'ws_channel' )
        self.file = request.FILES.get( 'upload_attatch' )

        self.dictionary.update( dict(
            real_file_name=self.file.name ,
            stored_file_name=self.dz_dictionary.dzuuid ,
            file_size=int( self.dz_dictionary.dztotalfilesize ) ,
            file_mime_type=self.file.content_type )
        )

        item = UploadItem( dictionary=self.dictionary )

        def load_str( pers ) :
            return f'Загружено: {pers} %'

        image_type , _ = Image_types.objects.get_or_create( code=self.image_type_name , keyimage=self.keyImage , defaults=dict( name=self.image_type_name ) )

        res = Images.objects.getOptional(
            size=item.file_size ,
            real_name=item.real_file_name ,
        )

        if res is not None :
            attfile = make_REPLACE_FILE_PATH( str( res.attfile ) )

            if isinstance( settings.FILES_STORE , str ) :
                ex = os.path.exists( attfile )
                if ex is False :
                    delete_img_refs( old_id=res.id )
                    res = None
            else :
                ssh_clients = settings.SSH_CLIENTS.client( settings.FILES_STORE )
                ex = ssh_clients.exists( attfile )
                if ex is False :
                    delete_img_refs( old_id=res.id )
                    res = None

        if res is None :
            with TemporaryFile() as src :
                src.seek( int( self.dz_dictionary.dzchunkbyteoffset ) )
                src.write( self.file.read() )

                pers = round( (int( self.dz_dictionary.dzchunkindex ) * 100) / int( self.dz_dictionary.dztotalchunkcount ) , 2 )
                if self.last_chunk :
                    pers = 100

                logger.debug( f'{load_str( pers )}, шаг : {int( self.dz_dictionary.dzchunkindex ) + 1} из {self.dz_dictionary.dztotalchunkcount}' )

                if self.last_chunk :
                    logger.debug( f'Загружен файл: {item.real_file_name}.' )
                    logger.debug( f'Запись временного файла.' )

                    with open( item.full_path , 'w+b' ) as destination :
                        src.seek( 0 )
                        destination.write( src.read() )
                        logger.debug( f'Запись временного файла выполнена.' )

                    logger.debug( f'Запись: {item.full_path}.' )
                    with open( item.full_path , 'rb' ) as src :
                        src.seek( 0 )
                        fileObj = File( src )

                        if isinstance( settings.FILES_STORE , str ) :
                            file_store = os.path.abspath( settings.FILES_STORE )
                        elif isinstance( settings.FILES_STORE , dict ) and settings.FILES_STORE.get( 'mode' ) == SFTP :
                            file_store = settings.FILES_STORE.get( 'PATH' )
                        else :
                            raise Exception( FILES_STORE_UNKNOWN_TYPE )

                        res = Images.objects.create(
                            attfile=fileObj ,
                            file_store=file_store ,
                            format=item.file_format ,
                            mime_type=item.file_mime_type ,
                            size=item.file_size ,
                            real_name=item.real_file_name ,
                        )

                        ws = create_connection( f"ws://{self.host}:{self.port}/ws/{self.channel}/" )
                        ws.send( json.dumps( dict( id=item.id , item_id=res.id , type="uploaded" ) ) )
                        ws.close()

                    logger.debug( f'Запись: {item.real_file_name} ({fileObj.name}) завершена.' )

                    self.remove( item.full_path )
                    logger.debug( f'Удаление: {item.full_path} завершено.' )

        return res , image_type , item.id

    @property
    def last_chunk( self ) :
        res = int( self.dz_dictionary.dztotalchunkcount ) == int( self.dz_dictionary.dzchunkindex ) + 1
        return res


@JsonResponseWithException()
class DSResponse_UploadImage( Common_UploadImage ) :
    def __init__( self , request ) :
        self.upload_image( request=request )


@JsonResponseWithException()
class DSResponse_CommonUploadImage( Common_UploadImage ) :
    def __init__( self , request , model , image_model , field_main_model='' ) :
        with transaction.atomic() :
            file = request.FILES.get( 'upload_attatch' )
            if file is not None :
                image , type , id = self.upload_image( request=request )

                main_model = eval( f"model.objects.get( id={id} ){f'.{field_main_model}' if field_main_model else ''}" )
                if main_model is None :
                    raise Exception( f'Для field_main_model {field_main_model} не найдено main_model' )

                main_model_image = image_model.objects.getOptional( main_model=main_model , image=image , type=type , deleted_at__isnull=False )

                if main_model_image is not None :
                    main_model_image.soft_restore()
                    main_model_image.save()
                else :
                    main_model_image = image_model.objects.create( main_model=main_model , type=type , image=image )

                image_model.objects.filter( main_model=main_model , type=type , deleted_at__isnull=True ).exclude( id=main_model_image.id ).soft_delete()

                logger.debug( f'Created: {main_model_image}' )
