# -*- coding: utf-8 -*-
#
# Copyright (C) 2021 - 2022 TU Wien.
# Copyright (C) 2021 Northwestern University.
#
# Invenio-Requests is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.

"""API classes for requests in Invenio."""

from enum import Enum
from functools import partial

from invenio_records.dumpers import SearchDumper
from invenio_records.systemfields import ConstantField, DictField, ModelField
from invenio_records_resources.records.api import Record
from invenio_records_resources.records.systemfields import IndexField

from ..customizations import RequestState as State
from .dumpers import CalculatedFieldDumperExt, GrantTokensDumperExt
from .models import RequestEventModel, RequestMetadata
from .systemfields import (
    EntityReferenceField,
    EventTypeField,
    ExpiredStateCalculatedField,
    IdentityField,
    RequestStateCalculatedField,
    RequestStatusField,
    RequestTypeField,
)
from .systemfields.entity_reference import (
    check_allowed_creators,
    check_allowed_receivers,
    check_allowed_references,
    check_allowed_topics,
)


class Request(Record):
    """A generic request record."""

    model_cls = RequestMetadata
    """The model class for the request."""

    dumper = SearchDumper(
        extensions=[
            CalculatedFieldDumperExt("is_closed"),
            CalculatedFieldDumperExt("is_open"),
            GrantTokensDumperExt("created_by", "receiver"),
        ]
    )
    """Search dumper with configured extensions."""

    number = IdentityField("number")
    """The request's number (i.e. external identifier)."""

    metadata = None
    """Disabled metadata field from the base class."""

    index = IndexField("requests-request-v1.0.0", search_alias="requests")
    """The Search index to use for the request."""

    schema = ConstantField("$schema", "local://requests/request-v1.0.0.json")
    """The JSON Schema to use for validation."""

    type = RequestTypeField("type")
    """System field for management of the request type.

    This field manages loading of the correct RequestType classes associated with
    `Requests`, based on their `request_type_id` field.
    This is important because the `RequestType` classes are the place where the
    custom request actions are registered.
    """

    topic = EntityReferenceField("topic", check_allowed_topics)
    """Topic (associated object) of the request."""

    created_by = EntityReferenceField("created_by", check_allowed_creators)
    """The entity that created the request."""

    receiver = EntityReferenceField("receiver", check_allowed_receivers)
    """The entity that will receive the request."""

    status = RequestStatusField("status")
    """The current status of the request."""

    is_closed = RequestStateCalculatedField("status", expected_state=State.CLOSED)
    """Whether or not the current status can be seen as a 'closed' state."""

    is_open = RequestStateCalculatedField("status", expected_state=State.OPEN)
    """Whether or not the current status can be seen as an 'open' state."""

    expires_at = ModelField("expires_at")
    """Expiration date of the request."""

    is_expired = ExpiredStateCalculatedField("expires_at")
    """Whether or not the request is already expired."""


class RequestEventFormat(Enum):
    """Comment/content format enum."""

    HTML = "html"


class RequestEvent(Record):
    """A Request Event."""

    model_cls = RequestEventModel

    # Systemfields
    metadata = None

    schema = ConstantField("$schema", "local://requestevents/requestevent-v1.0.0.json")
    """The JSON Schema to use for validation."""

    request = ModelField(dump=False)
    """The request."""

    request_id = DictField("request_id")
    """The data-layer id of the related Request."""

    type = EventTypeField("type")
    """Request event type system field."""

    index = IndexField(
        "requestevents-requestevent-v1.0.0", search_alias="requestevents"
    )
    """The ES index used."""

    id = ModelField("id")
    """The data-layer id."""

    check_referenced = partial(
        check_allowed_references,
        lambda r: True,  # for system process for now
        lambda r: ["user"],  # only users for now
    )

    created_by = EntityReferenceField("created_by", check_referenced)
    """Who created the event."""
