# Copyright 2024 Akretion (https://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import logging
import sys
from typing import Any, Dict, Union

from itsdangerous import URLSafeTimedSerializer
from starlette.status import HTTP_401_UNAUTHORIZED

from odoo.api import Environment

from odoo.addons.base.models.res_partner import Partner
from odoo.addons.fastapi.dependencies import fastapi_endpoint, odoo_env
from odoo.addons.fastapi.models import FastapiEndpoint

from fastapi import Cookie, Depends, HTTPException, Request, Response

if sys.version_info >= (3, 9):
    from typing import Annotated
else:
    from typing_extensions import Annotated

_logger = logging.getLogger(__name__)


Payload = Dict[str, Any]


class AuthPartner:
    def __init__(self, allow_unauthenticated: bool = False):
        self.allow_unauthenticated = allow_unauthenticated

    def __call__(
        self,
        request: Request,
        response: Response,
        env: Annotated[
            Environment,
            Depends(odoo_env),
        ],
        endpoint: Annotated[FastapiEndpoint, Depends(fastapi_endpoint)],
        fastapi_auth_partner: Annotated[Union[str, None], Cookie()] = None,
    ) -> Partner:
        if not fastapi_auth_partner and self.allow_unauthenticated:
            return env["res.partner"].with_user(env.ref("base.public_user")).browse()

        elif fastapi_auth_partner:
            directory = endpoint.sudo().directory_id
            try:
                vals = URLSafeTimedSerializer(
                    directory.cookie_secret_key or directory.secret_key
                ).loads(fastapi_auth_partner, max_age=directory.cookie_duration * 60)
            except Exception as e:
                _logger.error("Invalid cookies error %s", e)
                raise HTTPException(status_code=HTTP_401_UNAUTHORIZED) from e
            if vals["did"] == directory.id and vals["pid"]:
                partner = env["res.partner"].browse(vals["pid"]).exists()
                if partner:
                    auth_partner = partner._get_auth_partner_for_directory(directory)
                    if auth_partner:
                        if directory.sliding_session:
                            helper = env["fastapi.auth.service"].new(
                                {"endpoint_id": endpoint}
                            )
                            helper._set_auth_cookie(auth_partner, request, response)
                        return partner
        _logger.info("Could not determine partner from 'fastapi_auth_partner' cookie.")
        raise HTTPException(status_code=HTTP_401_UNAUTHORIZED)


auth_partner_authenticated_partner = AuthPartner()
auth_partner_optionally_authenticated_partner = AuthPartner(allow_unauthenticated=True)
