# !!!
# WARNING: This file is autogenerated
# Only modify code within MANUAL() sections
# or your changes may be overwritten later!
# !!!

from typing import Any, AsyncGenerator, Dict, Generator, List, Optional

from stytch.core.api_base import ApiBase
from stytch.core.http.client import AsyncClient, SyncClient
from stytch.core.models import Name, SearchQuery
from stytch.models.users import (
    CreateResponse,
    DeleteBiometricRegistrationResponse,
    DeleteCryptoWalletResponse,
    DeleteEmailResponse,
    DeleteOauthUserRegistrationResponse,
    DeletePasswordResponse,
    DeletePhoneNumberResponse,
    DeleteResponse,
    DeleteTotpResponse,
    DeleteWebauthnRegistrationResponse,
    GetPendingResponse,
    GetResponse,
    SearchResponse,
    UpdateResponse,
)


class Users:
    def __init__(
        self,
        api_base: ApiBase,
        sync_client: SyncClient,
        async_client: AsyncClient,
    ) -> None:
        self.api_base = api_base
        self.sync_client = sync_client
        self.async_client = async_client

    @property
    def sub_url(self) -> str:
        return "users"

    def create(
        self,
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        name: Optional[Name] = None,
        create_user_as_pending: bool = False,
        attributes: Optional[Dict[str, str]] = None,
        trusted_metadata: Optional[Dict[str, Any]] = None,
        untrusted_metadata: Optional[Dict[str, Any]] = None,
    ) -> CreateResponse:
        payload: Dict[str, Any] = {
            "create_user_as_pending": create_user_as_pending,
        }

        if email is not None:
            payload["email"] = email
        if phone_number is not None:
            payload["phone_number"] = phone_number
        if name is not None:
            payload["name"] = name.dict()
        if attributes is not None:
            payload["attributes"] = attributes
        if trusted_metadata is not None:
            payload["trusted_metadata"] = trusted_metadata
        if untrusted_metadata is not None:
            payload["untrusted_metadata"] = untrusted_metadata

        url = self.api_base.route_with_sub_url(self.sub_url, None)

        res = self.sync_client.post(url, json=payload)
        return CreateResponse.from_json(res.response.status_code, res.json)

    async def create_async(
        self,
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        name: Optional[Name] = None,
        create_user_as_pending: bool = False,
        attributes: Optional[Dict[str, str]] = None,
        trusted_metadata: Optional[Dict[str, Any]] = None,
        untrusted_metadata: Optional[Dict[str, Any]] = None,
    ) -> CreateResponse:
        payload: Dict[str, Any] = {
            "create_user_as_pending": create_user_as_pending,
        }

        if email is not None:
            payload["email"] = email
        if phone_number is not None:
            payload["phone_number"] = phone_number
        if name is not None:
            payload["name"] = name.dict()
        if attributes is not None:
            payload["attributes"] = attributes
        if trusted_metadata is not None:
            payload["trusted_metadata"] = trusted_metadata
        if untrusted_metadata is not None:
            payload["untrusted_metadata"] = untrusted_metadata

        url = self.api_base.route_with_sub_url(self.sub_url, None)

        res = await self.async_client.post(url, json=payload)
        return CreateResponse.from_json(res.response.status, res.json)

    def get(
        self,
        user_id: str,
    ) -> GetResponse:
        payload: Dict[str, Any] = {
            "user_id": user_id,
        }

        url = self.api_base.route_with_sub_url(self.sub_url, user_id)

        res = self.sync_client.get(url, params=payload)
        return GetResponse.from_json(res.response.status_code, res.json)

    async def get_async(
        self,
        user_id: str,
    ) -> GetResponse:
        payload: Dict[str, Any] = {
            "user_id": user_id,
        }

        url = self.api_base.route_with_sub_url(self.sub_url, user_id)

        res = await self.async_client.get(url, params=payload)
        return GetResponse.from_json(res.response.status, res.json)

    def get_pending(
        self,
        limit: Optional[int] = None,
        starting_after_id: Optional[str] = None,
    ) -> GetPendingResponse:
        payload: Dict[str, Any] = {}

        if limit is not None:
            payload["limit"] = limit
        if starting_after_id is not None:
            payload["starting_after_id"] = starting_after_id

        url = self.api_base.route_with_sub_url(self.sub_url, "pending")

        res = self.sync_client.get(url, params=payload)
        return GetPendingResponse.from_json(res.response.status_code, res.json)

    async def get_pending_async(
        self,
        limit: Optional[int] = None,
        starting_after_id: Optional[str] = None,
    ) -> GetPendingResponse:
        payload: Dict[str, Any] = {}

        if limit is not None:
            payload["limit"] = limit
        if starting_after_id is not None:
            payload["starting_after_id"] = starting_after_id

        url = self.api_base.route_with_sub_url(self.sub_url, "pending")

        res = await self.async_client.get(url, params=payload)
        return GetPendingResponse.from_json(res.response.status, res.json)

    def search(
        self,
        limit: Optional[int] = None,
        cursor: Optional[str] = None,
        query: Optional[SearchQuery] = None,
    ) -> SearchResponse:
        payload: Dict[str, Any] = {}

        if limit is not None:
            payload["limit"] = limit
        if cursor is not None:
            payload["cursor"] = cursor
        if query is not None:
            payload["query"] = query.dict()

        url = self.api_base.route_with_sub_url(self.sub_url, "search")

        res = self.sync_client.post(url, json=payload)
        return SearchResponse.from_json(res.response.status_code, res.json)

    async def search_async(
        self,
        limit: Optional[int] = None,
        cursor: Optional[str] = None,
        query: Optional[SearchQuery] = None,
    ) -> SearchResponse:
        payload: Dict[str, Any] = {}

        if limit is not None:
            payload["limit"] = limit
        if cursor is not None:
            payload["cursor"] = cursor
        if query is not None:
            payload["query"] = query.dict()

        url = self.api_base.route_with_sub_url(self.sub_url, "search")

        res = await self.async_client.post(url, json=payload)
        return SearchResponse.from_json(res.response.status, res.json)

    # MANUAL(search_all)
    def search_all(
        self,
        limit: Optional[int] = None,
        cursor: Optional[str] = None,
        query: Optional[SearchQuery] = None,
    ) -> Generator[SearchResponse, None, None]:
        # 1. Check if this method should be async or not
        # 2. Set the return type appropriately
        # 3. Fill out the method details
        # 4. Remember to write a test since this is manually generated
        while True:
            results = self.search(limit, cursor, query)
            yield results
            cursor = results.results_metadata.next_cursor
            if cursor is None:
                break

    async def search_all_async(
        self,
        limit: Optional[int] = None,
        cursor: Optional[str] = None,
        query: Optional[SearchQuery] = None,
    ) -> AsyncGenerator[SearchResponse, None]:
        # 1. Check if this method should be async or not
        # 2. Set the return type appropriately
        # 3. Fill out the method details
        # 4. Remember to write a test since this is manually generated
        while True:
            results = await self.search_async(limit, cursor, query)
            yield results
            cursor = results.results_metadata.next_cursor
            if cursor is None:
                break

    # ENDMANUAL(search_all)

    def delete(
        self,
        user_id: str,
    ) -> DeleteResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, user_id)

        res = self.sync_client.delete(url)
        return DeleteResponse.from_json(res.response.status_code, res.json)

    async def delete_async(
        self,
        user_id: str,
    ) -> DeleteResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, user_id)

        res = await self.async_client.delete(url)
        return DeleteResponse.from_json(res.response.status, res.json)

    def update(
        self,
        user_id: str,
        emails: Optional[List[str]] = None,
        phone_numbers: Optional[List[str]] = None,
        crypto_wallets: Optional[List[str]] = None,
        name: Optional[Name] = None,
        attributes: Optional[Dict[str, str]] = None,
        trusted_metadata: Optional[Dict[str, Any]] = None,
        untrusted_metadata: Optional[Dict[str, Any]] = None,
    ) -> UpdateResponse:
        payload: Dict[str, Any] = {
            "user_id": user_id,
        }

        if emails is not None:
            payload["emails"] = emails
        if phone_numbers is not None:
            payload["phone_numbers"] = phone_numbers
        if crypto_wallets is not None:
            payload["crypto_wallets"] = crypto_wallets
        if name is not None:
            payload["name"] = name.dict()
        if attributes is not None:
            payload["attributes"] = attributes
        if trusted_metadata is not None:
            payload["trusted_metadata"] = trusted_metadata
        if untrusted_metadata is not None:
            payload["untrusted_metadata"] = untrusted_metadata

        url = self.api_base.route_with_sub_url(self.sub_url, user_id)

        res = self.sync_client.put(url, json=payload)
        return UpdateResponse.from_json(res.response.status_code, res.json)

    async def update_async(
        self,
        user_id: str,
        emails: Optional[List[str]] = None,
        phone_numbers: Optional[List[str]] = None,
        crypto_wallets: Optional[List[str]] = None,
        name: Optional[Name] = None,
        attributes: Optional[Dict[str, str]] = None,
        trusted_metadata: Optional[Dict[str, Any]] = None,
        untrusted_metadata: Optional[Dict[str, Any]] = None,
    ) -> UpdateResponse:
        payload: Dict[str, Any] = {
            "user_id": user_id,
        }

        if emails is not None:
            payload["emails"] = emails
        if phone_numbers is not None:
            payload["phone_numbers"] = phone_numbers
        if crypto_wallets is not None:
            payload["crypto_wallets"] = crypto_wallets
        if name is not None:
            payload["name"] = name.dict()
        if attributes is not None:
            payload["attributes"] = attributes
        if trusted_metadata is not None:
            payload["trusted_metadata"] = trusted_metadata
        if untrusted_metadata is not None:
            payload["untrusted_metadata"] = untrusted_metadata

        url = self.api_base.route_with_sub_url(self.sub_url, user_id)

        res = await self.async_client.put(url, json=payload)
        return UpdateResponse.from_json(res.response.status, res.json)

    def delete_email(
        self,
        email_id: str,
    ) -> DeleteEmailResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, f"emails/{email_id}")

        res = self.sync_client.delete(url)
        return DeleteEmailResponse.from_json(res.response.status_code, res.json)

    async def delete_email_async(
        self,
        email_id: str,
    ) -> DeleteEmailResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, f"emails/{email_id}")

        res = await self.async_client.delete(url)
        return DeleteEmailResponse.from_json(res.response.status, res.json)

    def delete_phone_number(
        self,
        phone_id: str,
    ) -> DeletePhoneNumberResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"phone_numbers/{phone_id}"
        )

        res = self.sync_client.delete(url)
        return DeletePhoneNumberResponse.from_json(res.response.status_code, res.json)

    async def delete_phone_number_async(
        self,
        phone_id: str,
    ) -> DeletePhoneNumberResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"phone_numbers/{phone_id}"
        )

        res = await self.async_client.delete(url)
        return DeletePhoneNumberResponse.from_json(res.response.status, res.json)

    def delete_webauthn_registration(
        self,
        webauthn_registration_id: str,
    ) -> DeleteWebauthnRegistrationResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"webauthn_registrations/{webauthn_registration_id}"
        )

        res = self.sync_client.delete(url)
        return DeleteWebauthnRegistrationResponse.from_json(
            res.response.status_code, res.json
        )

    async def delete_webauthn_registration_async(
        self,
        webauthn_registration_id: str,
    ) -> DeleteWebauthnRegistrationResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"webauthn_registrations/{webauthn_registration_id}"
        )

        res = await self.async_client.delete(url)
        return DeleteWebauthnRegistrationResponse.from_json(
            res.response.status, res.json
        )

    def delete_totp(
        self,
        totp_id: str,
    ) -> DeleteTotpResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, f"totps/{totp_id}")

        res = self.sync_client.delete(url)
        return DeleteTotpResponse.from_json(res.response.status_code, res.json)

    async def delete_totp_async(
        self,
        totp_id: str,
    ) -> DeleteTotpResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, f"totps/{totp_id}")

        res = await self.async_client.delete(url)
        return DeleteTotpResponse.from_json(res.response.status, res.json)

    def delete_crypto_wallet(
        self,
        crypto_wallet_id: str,
    ) -> DeleteCryptoWalletResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"crypto_wallets/{crypto_wallet_id}"
        )

        res = self.sync_client.delete(url)
        return DeleteCryptoWalletResponse.from_json(res.response.status_code, res.json)

    async def delete_crypto_wallet_async(
        self,
        crypto_wallet_id: str,
    ) -> DeleteCryptoWalletResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"crypto_wallets/{crypto_wallet_id}"
        )

        res = await self.async_client.delete(url)
        return DeleteCryptoWalletResponse.from_json(res.response.status, res.json)

    def delete_password(
        self,
        password_id: str,
    ) -> DeletePasswordResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, f"passwords/{password_id}")

        res = self.sync_client.delete(url)
        return DeletePasswordResponse.from_json(res.response.status_code, res.json)

    async def delete_password_async(
        self,
        password_id: str,
    ) -> DeletePasswordResponse:

        url = self.api_base.route_with_sub_url(self.sub_url, f"passwords/{password_id}")

        res = await self.async_client.delete(url)
        return DeletePasswordResponse.from_json(res.response.status, res.json)

    def delete_biometric_registration(
        self,
        biometric_registration_id: str,
    ) -> DeleteBiometricRegistrationResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"biometric_registrations/{biometric_registration_id}"
        )

        res = self.sync_client.delete(url)
        return DeleteBiometricRegistrationResponse.from_json(
            res.response.status_code, res.json
        )

    async def delete_biometric_registration_async(
        self,
        biometric_registration_id: str,
    ) -> DeleteBiometricRegistrationResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"biometric_registrations/{biometric_registration_id}"
        )

        res = await self.async_client.delete(url)
        return DeleteBiometricRegistrationResponse.from_json(
            res.response.status, res.json
        )

    def delete_oauth_user_registration(
        self,
        oauth_user_registration_id: str,
    ) -> DeleteOauthUserRegistrationResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"oauth/{oauth_user_registration_id}"
        )

        res = self.sync_client.delete(url)
        return DeleteOauthUserRegistrationResponse.from_json(
            res.response.status_code, res.json
        )

    async def delete_oauth_user_registration_async(
        self,
        oauth_user_registration_id: str,
    ) -> DeleteOauthUserRegistrationResponse:

        url = self.api_base.route_with_sub_url(
            self.sub_url, f"oauth/{oauth_user_registration_id}"
        )

        res = await self.async_client.delete(url)
        return DeleteOauthUserRegistrationResponse.from_json(
            res.response.status, res.json
        )
