# Copyright (C) 2023 Cochise Ruhulessin
#
# All rights reserved. No warranty, explicit or implicit, provided. In
# no event shall the author(s) be liable for any claim or damages.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import datetime
import secrets
from typing import Any
from typing import ClassVar

import pydantic
from canonical import UnixTimestamp

from .sessionkey import SessionKey


class Session(pydantic.BaseModel):
    Key: ClassVar[type[SessionKey]] = SessionKey
    id: str
    sub: str | None = None
    email: str | None = None
    auth_time: UnixTimestamp | None = None
    _is_dirty: bool = pydantic.PrivateAttr(default=False)

    @classmethod
    def new(cls):
        return cls.model_validate({'id': secrets.token_urlsafe(64)})

    def authenticate(self, sub: str, email: str | None) -> None:
        """Authenticates the session as the given subject."""
        self.set('auth_time', UnixTimestamp.now(datetime.timezone.utc))
        self.set('sub', sub)
        if email is not None:
            self.set('email', email)

    def claims(self) -> dict[str, Any]:
        return self.model_dump(include={'id', 'sub', 'email', 'auth_time'})

    def is_dirty(self) -> bool:
        return self._is_dirty

    def set(self, key: str, value: Any) -> None:
        if key not in self.model_fields:
            raise AttributeError(key)
        if getattr(self, key) == value:
            return
        setattr(self, key, value)
        self._is_dirty = True
        