from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.utils.functional import LazyObject

from accounts.const import AliasAccount
from accounts.models import Account, VirtualAccount
from common.decorators import on_transaction_commit
from common.signals import django_ready
from common.utils import get_logger
from common.utils.connection import RedisPubSub
from orgs.utils import tmp_to_builtin_org
from users.models import User
from ..models import Applet, AppletHost
from ..tasks import applet_host_generate_accounts
from ..utils import DBPortManager

db_port_manager: DBPortManager
logger = get_logger(__file__)


@receiver(post_save, sender=AppletHost)
@on_transaction_commit
def on_applet_host_create(sender, instance, created=False, **kwargs):
    if not created:
        return
    # 新建时,清除原来的首选,避免一直调度到一个上面
    Applet.clear_host_prefer()
    applets = Applet.objects.all()
    instance.applets.set(applets)
    applet_host_change_pub_sub.publish(True)


@receiver(post_save, sender=AppletHost)
@on_transaction_commit
def on_applet_host_update_or_create(sender, instance, created=False, **kwargs):
    if instance.auto_create_accounts:
        applet_host_generate_accounts.delay(instance.id)

    # 使用同名账号的,直接给他打开登录那项吧
    if instance.using_same_account:
        alias = AliasAccount.USER.value
        same_account, __ = VirtualAccount.objects.get_or_create(
            alias=alias, defaults={'alias': alias, 'secret_from_login': True}
        )
        if same_account.secret_from_login:
            return
        same_account.secret_from_login = True
        same_account.save(update_fields=['secret_from_login'])


@receiver(post_save, sender=User)
def on_user_create_create_account(sender, instance: User, created=False, **kwargs):
    if not created:
        return
    if instance.is_service_account:
        return
    with tmp_to_builtin_org(system=1):
        applet_hosts = AppletHost.objects.all()
        for host in applet_hosts:
            if not host.auto_create_accounts:
                continue
            host.generate_private_accounts_by_usernames([instance.username])


@receiver(post_delete, sender=User)
def on_user_delete_remove_account(sender, instance, **kwargs):
    account_username = 'js_{}'.format(instance.username)
    with tmp_to_builtin_org(system=1):
        applet_hosts = AppletHost.objects.all().values_list('id', flat=True)
        accounts = Account.objects.filter(asset_id__in=applet_hosts, username=account_username)
        accounts.delete()


@receiver(post_delete, sender=AppletHost)
def on_applet_host_delete(sender, instance, **kwargs):
    applet_host_change_pub_sub.publish(True)


@receiver(post_save, sender=Applet)
def on_applet_create(sender, instance, created=False, **kwargs):
    if not created:
        return
    hosts = AppletHost.objects.all()
    instance.hosts.set(hosts)
    applet_host_change_pub_sub.publish(True)


@receiver(post_delete, sender=Applet)
def on_applet_delete(sender, instance, **kwargs):
    applet_host_change_pub_sub.publish(True)


class AppletHostPubSub(LazyObject):
    def _setup(self):
        self._wrapped = RedisPubSub('fm.applet_host_change')


@receiver(django_ready)
def subscribe_applet_host_change(sender, **kwargs):
    logger.debug("Start subscribe for expire node assets id mapping from memory")

    def on_change(message):
        from terminal.connect_methods import ConnectMethodUtil
        ConnectMethodUtil.refresh_methods()

    applet_host_change_pub_sub.subscribe(on_change)


applet_host_change_pub_sub = AppletHostPubSub()