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

import datetime
import typing
import uuid

from django.utils.timezone import get_current_timezone

from hotpocket_backend.apps.saves.models import Association


class AssociationsTestingService:
    EDITABLE_FIELDS = [
        'target_title', 'target_description',
    ]

    def assert_archived(self, *, pk: uuid.UUID, reference: typing.Any = None):
        association = Association.objects.get(pk=pk)
        assert association.archived_at is not None

        if reference is not None:
            assert association.updated_at > reference.updated_at

    def assert_not_archived(self, *, pk: uuid.UUID, reference: typing.Any = None):
        association = Association.objects.get(pk=pk)
        assert association.archived_at is None

        if reference is not None:
            assert association.updated_at > reference.updated_at

    def assert_deleted(self, *, pk: uuid.UUID, reference: typing.Any = None):
        association = Association.objects.get(pk=pk)
        assert association.deleted_at is not None

        if reference is not None:
            assert association.updated_at > reference.updated_at

    def assert_not_deleted(self, *, pk: uuid.UUID, reference: typing.Any = None):
        association = Association.objects.get(pk=pk)
        assert association.deleted_at is None

        if reference is not None:
            assert association.updated_at == reference.updated_at

    def assert_starred(self, *, pk: uuid.UUID, reference: typing.Any = None):
        association = Association.objects.get(pk=pk)
        assert association.starred_at is not None

        if reference is not None:
            assert association.updated_at > reference.updated_at

    def assert_not_starred(self, *, pk: uuid.UUID, reference: typing.Any = None):
        association = Association.objects.get(pk=pk)
        assert association.starred_at is None

        if reference is not None:
            assert association.updated_at > reference.updated_at

    def assert_edited(self, *, pk: uuid.UUID, update: dict, reference: typing.Any):
        association = Association.objects.get(pk=pk)

        for field in self.EDITABLE_FIELDS:
            expected_value = update.get(field, '') or None
            actual_value = getattr(association, field)
            assert actual_value == expected_value, (
                f'Value mismatch: field=`{field}` '
                f'expected_value=`{expected_value}` '
                f'actual_value=`{actual_value}`'
            )

        assert association.updated_at > reference.updated_at
        assert association.target.url == reference.target.url

    def assert_created(self,
                       *,
                       pk: uuid.UUID,
                       account_uuid: uuid.UUID,
                       target_uuid: uuid.UUID,
                       ):
        association = Association.objects.get(pk=pk)
        assert association.account_uuid == account_uuid
        assert association.target_id == target_uuid

        for field in self.EDITABLE_FIELDS:
            actual_value = getattr(association, field)
            assert actual_value is None, (
                f'Value mismatch: field=`{field}` '
                f'actual_value=`{actual_value}`'
            )

        assert association.created_at is not None
        assert association.updated_at is not None

    def assert_reused(self,
                      pk: uuid.UUID,
                      reference: typing.Any,
                      ):
        association = Association.objects.get(pk=pk)
        assert association.pk == reference.pk
        assert association.account_uuid == reference.account_uuid
        assert association.target_id == reference.target_uuid

        for field in self.EDITABLE_FIELDS:
            expected_value = getattr(reference, field)
            actual_value = getattr(association, field)
            assert actual_value is expected_value, (
                f'Value mismatch: field=`{field}` '
                f'actual_value=`{actual_value}` '
                f'expected_value=`{expected_value}`'
            )

        assert association.created_at == reference.created_at
        assert association.updated_at == reference.updated_at

    def assert_imported(self,
                        *,
                        pk: uuid.UUID,
                        account_uuid: uuid.UUID,
                        target_uuid: uuid.UUID,
                        created_at: datetime.datetime,
                        ):
        self.assert_created(pk=pk, account_uuid=account_uuid, target_uuid=target_uuid)

        association = Association.objects.get(pk=pk)
        assert association.created_at == created_at.astimezone(get_current_timezone())
