import itertools
import logging

from django.conf import settings
from django.db.models import Q
from django.utils.functional import SimpleLazyObject

from staff.lib import requests, tvm2
from staff.lib.exceptions import ErrorWithStatusCode
from staff.person.models import StaffExtraFields
from staff.person_avatar.controllers import PersonAvatarCollection
from staff.person_avatar.models import AvatarMetadata, PreprofileExtraFields
from staff.person_avatar.storage import (
    AvatarBadRequestError,
    AvatarConnectingError,
    AvatarStorageError,
)


logger = logging.getLogger('person_profile.controllers.photos')

TVM_HEADERS = SimpleLazyObject(lambda: {tvm2.TVM_SERVICE_TICKET_HEADER: tvm2.get_tvm_ticket_by_deploy('avatars-mds')})


class PhotoError(ErrorWithStatusCode):
    pass


class PhotosCtl(object):

    def __init__(self, person):
        self.target_person = person

    def upload_photo(self, picture_file=None, picture_url=None):
        person_avatars = PersonAvatarCollection(owner=self.target_person)

        if person_avatars.count() >= PersonAvatarCollection.AVATARS_MAX_COUNT:
            raise PhotoError('avatars-max-count-exceeded', 400)

        try:
            person_avatars.upload(picture_file=picture_file, picture_url=picture_url)
        except (AvatarConnectingError, AvatarStorageError):
            logger.info('Avatar storage error', exc_info=True)
            raise PhotoError('cannot-upload-photo', 502)
        except AvatarBadRequestError as request_error:
            logger.info('Avatar bad request error %s', request_error.code, exc_info=True)
            raise PhotoError('cannot-upload-photo', int(request_error.code))
        except Exception:
            logger.exception('Error while uploading photo for user %s', self.target_person.login)
            raise PhotoError('cannot-upload-photo', 503)

    def delete_all_photos(self) -> None:
        login = self.target_person.login
        logger.info('Deleting all %s user photos', login)
        login_filter = Q(person__login=login) | Q(preprofile__login=login)
        image_ids = AvatarMetadata.objects.filter(login_filter).values_list('id', flat=True)

        for image_name in itertools.chain([login], image_ids):
            for image_type in ('-main', '-avatar', ''):
                storage_response = requests.get(
                    f'{settings.AVATAR_STORAGE_URL}/delete-staff/{image_name}{image_type}',
                    headers=TVM_HEADERS,
                    timeout=settings.AVATAR_UPLOAD_TIMEOUT,
                )

                if storage_response.status_code != 404:
                    storage_response.raise_for_status()

        PreprofileExtraFields.objects.filter(preprofile__login=login).update(
            gravatar_img_for_upload=None,
            avatar_img_for_upload=None,
            main_img_for_upload=None,
        )
        StaffExtraFields.objects.filter(staff__login=login).update(
            gravatar_img_for_upload=None,
            avatar_img_for_upload=None,
            main_img_for_upload=None,
        )
        AvatarMetadata.objects.filter(login_filter).delete()
