# -*- coding: utf-8; -*-
################################################################################
#
#  WuttaFarm --Web app to integrate with and extend farmOS
#  Copyright © 2026 Lance Edgar
#
#  This file is part of WuttaFarm.
#
#  WuttaFarm is free software: you can redistribute it and/or modify it under
#  the terms of the GNU General Public License as published by the Free Software
#  Foundation, either version 3 of the License, or (at your option) any later
#  version.
#
#  WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY
#  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
#  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along with
#  WuttaFarm.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Auth handler for use with farmOS
"""

from uuid import UUID

from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
from sqlalchemy import orm

from wuttjamaican.auth import AuthHandler


class WuttaFarmAuthHandler(AuthHandler):
    """
    Custom auth handler for WuttaFarm.  This adds some magic around
    the user login process.

    It can attempt authentication against the configured farmOS
    instance, auto-creating native users within the app DB as needed.

    """

    def get_role_farm_manager(self, session):
        """
        Returns the special "Farm Manager" role.
        """
        return self._special_role(
            session, UUID("06979646-b1b9-723b-8000-b86161427f9f"), "Farm Manager"
        )

    def get_role_farm_worker(self, session):
        """
        Returns the special "Farm Worker" role.
        """
        return self._special_role(
            session, UUID("06979648-9bd6-7b61-8000-ee8818052ee8"), "Farm Worker"
        )

    def get_role_farm_viewer(self, session):
        """
        Returns the special "Farm Viewer" role.
        """
        return self._special_role(
            session, UUID("06979649-ed32-7e97-8000-113ddf0ab5f3"), "Farm Viewer"
        )

    def authenticate_user(self, session, username, password):
        """
        When authentication is attempted, this first will check
        credentials against the app DB per normal logic.  If that
        succeeds, the result is no different from the typical
        behavior.

        If default logic fails, this will try to obtain an OAuth2
        token from the farmOS site.  If that succeeds, then a lookup
        is done in the app DB for a matching user.  If the user does
        not yet exist it will be created automatically.
        """
        if user := super().authenticate_user(session, username, password):
            return user

        if token := self.get_farmos_oauth2_token(username, password):
            if user := self.get_or_make_farmos_user(session, username):
                user.__dict__["farmos_oauth2_token"] = token
                return user

        return None

    def get_farmos_oauth2_token(self, username, password):
        client = self.app.get_farmos_client()
        try:
            return client.authorize(username=username, password=password)
        except InvalidGrantError:
            return None

    def get_or_make_farmos_user(self, session, username):
        model = self.app.model
        try:
            user = (
                session.query(model.User).filter(model.User.username == username).one()
            )
        except orm.exc.NoResultFound:
            pass
        else:
            return user if user.active else None

        # nb. prevent edit for farmOS mirrored user accounts
        user = self.make_user(session, username=username, prevent_edit=True)

        # TODO
        manager = self.get_role_farm_manager(session)
        user.roles.append(manager)

        return user
