from __future__ import annotations

import time
from typing import Optional

from app.clients.pywechat_client import ClientRegistry, LoginStatus, OnlineStatus, registry
from app.models.event import EventType, OutboundEvent
from app.repositories.event_store import EventStore


class LoginService:
    def __init__(self, registry: ClientRegistry):
        self.registry = registry
        self.store: EventStore | None = None

    def start_login(self, account_id: str, account_name: Optional[str] = None, tenant_code: str = "default") -> dict:
        client = self.registry.get_or_create(account_id, account_name)
        login_id = client.start_login()
        self._emit_login_changed(account_id, tenant_code, LoginStatus.PENDING, client.state.login_status, client.state.qr_code_url)
        return {
            "login_id": login_id,
            "qr_code_url": client.state.qr_code_url,
            "status": client.state.login_status.value,
        }

    def get_status(self, account_id: str) -> dict:
        client = self.registry.get(account_id)
        if client is None:
            return {"found": False, "account_id": account_id}
        state = client.get_state()
        return {
            "found": True,
            "account_id": state.account_id,
            "account_name": state.account_name,
            "login_status": state.login_status.value,
            "online_status": state.online_status.value,
            "last_heartbeat_at": state.last_heartbeat_at,
            "risk_level": state.risk_level,
            "sent_count_today": state.sent_count_today,
        }

    def confirm_login(self, account_id: str, tenant_code: str = "default") -> dict:
        client = self.registry.get(account_id)
        if client is None:
            return {"success": False, "error": "account not found"}
        previous_login = client.state.login_status
        previous_online = client.state.online_status
        client.set_login_status(LoginStatus.SUCCESS)
        self._emit_login_changed(account_id, tenant_code, previous_login, client.state.login_status)
        self._emit_online_changed(account_id, tenant_code, previous_online, client.state.online_status)
        return {"success": True, "status": client.state.login_status.value}

    def expire_login(self, account_id: str, tenant_code: str = "default") -> dict:
        client = self.registry.get(account_id)
        if client is None:
            return {"success": False, "error": "account not found"}
        previous = client.state.login_status
        client.set_login_status(LoginStatus.EXPIRED)
        self._emit_login_changed(account_id, tenant_code, previous, client.state.login_status)
        return {"success": True, "status": client.state.login_status.value}

    def _emit_login_changed(self, account_id: str, tenant_code: str, previous: LoginStatus, current: LoginStatus, qr_code_url: Optional[str] = None) -> None:
        event = OutboundEvent(
            event_type=EventType.LOGIN_STATUS_CHANGED,
            account_id=account_id,
            tenant_code=tenant_code,
            data={
                "previous": previous.value,
                "current": current.value,
                "qr_code_url": qr_code_url,
            },
        )
        if self.store is not None:
            self.store.save(event)

    def _emit_online_changed(self, account_id: str, tenant_code: str, previous: OnlineStatus, current: OnlineStatus) -> None:
        event = OutboundEvent(
            event_type=EventType.ONLINE_STATUS_CHANGED,
            account_id=account_id,
            tenant_code=tenant_code,
            data={
                "previous": previous.value,
                "current": current.value,
            },
        )
        if self.store is not None:
            self.store.save(event)


login_service = LoginService(registry)
from app.repositories.event_store import event_store  # noqa: E402
login_service.store = event_store
