"""Cloud onboarding views."""

from collections.abc import Callable, Coroutine
from functools import wraps
from typing import TYPE_CHECKING, Any, Concatenate, override

from aiohttp import web
from aiohttp.web_exceptions import HTTPUnauthorized

from homeassistant.components.http import KEY_HASS
from homeassistant.components.onboarding import (
    BaseOnboardingView,
    NoAuthBaseOnboardingView,
)
from homeassistant.core import HomeAssistant

from . import http_api as cloud_http
from .const import DATA_CLOUD

if TYPE_CHECKING:
    from homeassistant.components.onboarding import OnboardingStoreData


async def async_setup_views(hass: HomeAssistant, data: OnboardingStoreData) -> None:
    """Set up the cloud views."""

    hass.http.register_view(CloudForgotPasswordView(data))
    hass.http.register_view(CloudLoginView(data))
    hass.http.register_view(CloudLogoutView(data))
    hass.http.register_view(CloudStatusView(data))


def ensure_not_done[_ViewT: BaseOnboardingView, **_P](
    func: Callable[
        Concatenate[_ViewT, web.Request, _P],
        Coroutine[Any, Any, web.Response],
    ],
) -> Callable[Concatenate[_ViewT, web.Request, _P], Coroutine[Any, Any, web.Response]]:
    """Home Assistant API decorator to check onboarding and cloud."""

    @wraps(func)
    async def _ensure_not_done(
        self: _ViewT,
        request: web.Request,
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> web.Response:
        """Check onboarding status, cloud and call function."""
        if self._data["done"]:
            # If at least one onboarding step is done, we don't allow accessing
            # the cloud onboarding views.
            raise HTTPUnauthorized

        return await func(self, request, *args, **kwargs)

    return _ensure_not_done


class CloudForgotPasswordView(
    NoAuthBaseOnboardingView, cloud_http.CloudForgotPasswordView
):
    """View to start Forgot Password flow."""

    url = "/api/onboarding/cloud/forgot_password"
    name = "api:onboarding:cloud:forgot_password"

    @ensure_not_done
    @override
    async def post(self, request: web.Request) -> web.Response:
        """Handle forgot password request."""
        return await super()._post(request)


class CloudLoginView(NoAuthBaseOnboardingView, cloud_http.CloudLoginView):
    """Login to Home Assistant Cloud."""

    url = "/api/onboarding/cloud/login"
    name = "api:onboarding:cloud:login"

    @ensure_not_done
    @override
    async def post(self, request: web.Request) -> web.Response:
        """Handle login request."""
        return await super()._post(request)


class CloudLogoutView(NoAuthBaseOnboardingView, cloud_http.CloudLogoutView):
    """Log out of the Home Assistant cloud."""

    url = "/api/onboarding/cloud/logout"
    name = "api:onboarding:cloud:logout"

    @ensure_not_done
    @override
    async def post(self, request: web.Request) -> web.Response:
        """Handle logout request."""
        return await super()._post(request)


class CloudStatusView(NoAuthBaseOnboardingView):
    """Get cloud status view."""

    url = "/api/onboarding/cloud/status"
    name = "api:onboarding:cloud:status"

    @ensure_not_done
    async def get(self, request: web.Request) -> web.Response:
        """Return cloud status."""
        hass = request.app[KEY_HASS]
        cloud = hass.data[DATA_CLOUD]
        return self.json({"logged_in": cloud.is_logged_in})
