from ninja.pagination import LimitOffsetPagination
from ninja_schema import ModelSchema

from ninja_extra import (
    ModelConfig,
    ModelControllerBase,
    ModelEndpointFactory,
    ModelPagination,
    ModelSchemaConfig,
    ModelService,
    api_controller,
)
from ninja_extra.schemas import NinjaPaginationResponseSchema

from ..models import Event


class CreateEventSchema(ModelSchema):
    class Config:
        model = Event
        include = ["title", "start_date", "end_date"]


class EventSchema(ModelSchema):
    class Config:
        model = Event
        exclude = ["category"]


@api_controller("/event")
class EventModelControllerAutoGeneratedSchema(ModelControllerBase):
    model_config = ModelConfig(
        model=Event,
        schema_config=ModelSchemaConfig(read_only_fields=["id", "category"]),
    )


@api_controller("/event-case-2")
class EventModelControllerWithDefinedSchema(ModelControllerBase):
    model_config = ModelConfig(
        model=Event,
        create_schema=CreateEventSchema,
        retrieve_schema=EventSchema,
        update_schema=CreateEventSchema,
        patch_schema=CreateEventSchema,
        pagination=None,  # turn off pagination
    )


@api_controller("/event-case-3")
class EventModelControllerDifferentPagination(ModelControllerBase):
    model_config = ModelConfig(
        allowed_routes=[
            "list",
        ],
        model=Event,
        retrieve_schema=EventSchema,
        pagination=ModelPagination(
            klass=LimitOffsetPagination, pagination_schema=NinjaPaginationResponseSchema
        ),
    )


@api_controller("/event-case-4")
class EventModelControllerRetrieveAndList(ModelControllerBase):
    model_config = ModelConfig(
        allowed_routes=[
            "find_one",
            "list",
        ],
        model=Event,
        retrieve_schema=EventSchema,
    )


@api_controller("/event-custom")
class EventController(ModelService):
    def __init__(self):
        ModelService.__init__(self, model=Event)

    create_event = ModelEndpointFactory.create(
        schema_in=CreateEventSchema,
        schema_out=EventSchema,
        custom_handler=lambda self, schema, **kw: self.create(schema, **kw),
    )

    update_event = ModelEndpointFactory.update(
        path="/{int:event_id}",
        lookup_param="event_id",
        schema_in=CreateEventSchema,
        schema_out=EventSchema,
        object_getter=lambda self, pk, **kw: Event.objects.filter(id=pk).first(),
        custom_handler=lambda self, **kw: self.update(**kw),
    )

    patch_event = ModelEndpointFactory.patch(
        path="/{int:event_id}",
        lookup_param="event_id",
        schema_in=CreateEventSchema,
        schema_out=EventSchema,
        object_getter=lambda self, pk, **kw: Event.objects.filter(id=pk).first(),
        custom_handler=lambda self, **kw: self.patch(**kw),
    )

    retrieve_event = ModelEndpointFactory.find_one(
        path="/{int:event_id}",
        lookup_param="event_id",
        schema_out=EventSchema,
        object_getter=lambda self, pk, **kw: Event.objects.filter(id=pk).first(),
    )

    list_events = ModelEndpointFactory.list(
        path="/?event_id=str",
        schema_out=EventSchema,
        queryset_getter=lambda self, **kw: Event.objects.filter(
            id=kw["event_id"]
        ).all(),
    )

    delete_event = ModelEndpointFactory.delete(
        path="/{int:event_id}",
        lookup_param="event_id",
        object_getter=lambda self, pk, **kw: Event.objects.filter(id=pk).first(),
        custom_handler=lambda self, **kw: self.delete(**kw),
    )
