from pypos.core.base_service import BaseService
from pypos.core.utils.ui_message_utils import sanitize_ui_message
from pypos.modules.auth.models.auth_model import AuthModel
from pypos.modules.auth.services.auth_service import AuthService
from pypos.modules.auth.services.login_attempt_guard_service import LoginAttemptGuardService


class OfflineAdminAuthService(BaseService):
    def __init__(self, model=None, auth_service=None, attempt_guard_service=None):
        super().__init__()
        self.model = model or AuthModel()
        self.auth_service = auth_service or AuthService()
        self.attempt_guard_service = attempt_guard_service or LoginAttemptGuardService()

    def validate_admin_credentials(self, username, password):
        uname = str(username or "").strip()
        pwd = str(password or "")
        scope = LoginAttemptGuardService.SCOPE_OFFLINE_ADMIN
        global_scope = LoginAttemptGuardService.SCOPE_OFFLINE_ADMIN_GLOBAL
        global_identity = "__global__"

        guard_state = self.attempt_guard_service.check_attempt(scope, uname)
        if guard_state.get("locked"):
            return (
                False,
                self.attempt_guard_service.build_lock_message("otorisasi admin", guard_state),
                None,
            )
        guard_state_global = self.attempt_guard_service.check_attempt(global_scope, global_identity)
        if guard_state_global.get("locked"):
            return (
                False,
                self.attempt_guard_service.build_lock_message("otorisasi admin", guard_state_global),
                None,
            )

        if not uname or not pwd:
            return False, "Username dan password admin wajib diisi.", None

        admin_status = self.model.get_admin_offline_status(uname)
        if not admin_status:
            self.attempt_guard_service.record_failure(scope, uname)
            self.attempt_guard_service.record_failure(global_scope, global_identity)
            return False, "Username admin tidak ditemukan.", None

        if int(admin_status.get("oto_settlement", 0) or 0) != 1:
            self.attempt_guard_service.record_failure(scope, uname)
            self.attempt_guard_service.record_failure(global_scope, global_identity)
            return (
                False,
                "Hanya admin dengan hak akses settlement yang dapat melakukan otorisasi offline.",
                None,
            )

        try:
            ok, new_hash = self.auth_service.verify_and_upgrade(pwd, admin_status["password"])
        except RuntimeError as e:
            self.attempt_guard_service.record_failure(scope, uname)
            self.attempt_guard_service.record_failure(global_scope, global_identity)
            safe_message, _ = sanitize_ui_message("warning", str(e))
            return False, safe_message, None

        if not ok:
            failed = self.attempt_guard_service.record_failure(scope, uname)
            failed_global = self.attempt_guard_service.record_failure(global_scope, global_identity)
            if failed_global.get("locked"):
                return (
                    False,
                    self.attempt_guard_service.build_lock_message("otorisasi admin", failed_global),
                    None,
                )
            if failed.get("locked"):
                return (
                    False,
                    self.attempt_guard_service.build_lock_message("otorisasi admin", failed),
                    None,
                )
            return False, "Password admin salah.", None

        if new_hash:
            self.model.update_password_hash_by_id(admin_status["id"], new_hash)

        # edited by glg
        # Reset counter saat kredensial admin valid agar lockout tidak bertahan setelah sukses.
        self.attempt_guard_service.reset_attempt(scope, uname)
        return True, "", admin_status
