# -*- coding: utf-8 -*-
from __future__ import annotations

import hashlib
import typing
import uuid

from django.core.exceptions import ValidationError
from django.db import models

from hotpocket_backend.apps.core.services import get_adapter
from hotpocket_backend.apps.saves.models import Save
from hotpocket_backend.apps.saves.types import PSaveAdapter
from hotpocket_soa.dto.saves import ImportedSaveIn, SaveIn, SavesQuery
from hotpocket_soa.exceptions.backend import (
    Invalid as InvalidError,
    NotFound as NotFoundError,
)


class SavesService:
    class SavesServiceError(Exception):
        pass

    class Invalid(InvalidError, SavesServiceError):
        pass

    class NotFound(NotFoundError, SavesServiceError):
        pass

    @property
    def adapter(self) -> PSaveAdapter:
        if hasattr(self, '_adapter') is False:
            adapter_klass = get_adapter(
                'SAVES_SAVE_ADAPTER',
                'hotpocket_backend.apps.saves.adapters.basic:BasicSaveAdapter',
            )
            self._adapter = adapter_klass()

        return self._adapter

    def create(self,
               *,
               account_uuid: uuid.UUID,
               save: SaveIn | ImportedSaveIn,
               ) -> Save:
        try:
            key = hashlib.sha256(save.url.encode('utf-8')).hexdigest()

            defaults = dict(
                account_uuid=account_uuid,
                key=key,
                url=save.url,
            )

            save_object, created = Save.objects.get_or_create(
                key=key,
                deleted_at__isnull=True,
                defaults=defaults,
            )

            if created is True:
                save_object.is_netloc_banned = save.is_netloc_banned

                if isinstance(save, ImportedSaveIn) is True:
                    save_object.title = save.title  # type: ignore[union-attr]

                save_object.save()

            return save_object
        except ValidationError as exception:
            raise self.Invalid.from_django_validation_error(exception)

    def get(self, *, pk: uuid.UUID) -> Save:
        try:
            return Save.active_objects.get(pk=pk)
        except Save.DoesNotExist as exception:
            raise self.NotFound(
                f'Save not found: pk=`{pk}`',
            ) from exception

    def search(self,
               *,
               filters: typing.Any,
               offset: int = 0,
               limit: int = 10,
               order: str = '-created_at',
               ) -> models.QuerySet[Save]:
        raise NotImplementedError('TODO')

    def update(self, *, pk: uuid.UUID, save: SaveIn) -> Save:
        raise NotImplementedError('TODO')

    def delete(self, *, pk: uuid.UUID) -> bool:
        raise NotImplementedError('TODO')

    def search_associated_to_account(self,
                                     *,
                                     account_uuid: uuid.UUID,
                                     query: SavesQuery,
                                     offset: int = 0,
                                     limit: int = 10,
                                     order_by: str = '-associations__created_at',
                                     ) -> models.QuerySet[Save]:
        result = Save.active_objects.\
            filter(
                associations__account_uuid=account_uuid,
                associations__archived_at__isnull=True,
            ).\
            order_by(order_by)

        return result

    def get_for_processing(self, *, pk: uuid.UUID) -> Save:
        return self.adapter.get_for_processing(pk=pk)
