from django.contrib.auth import get_user_model
from django.db import models
from guardian.shortcuts import assign_perm

from grandchallenge.core.models import TitleSlugDescriptionModel, UUIDModel
from grandchallenge.core.validators import JSONValidator


class ImagePort(models.TextChoices):
    MAIN = "M", "Main"
    SECONDARY = "S", "Secondary"
    TERTIARY = "TERTIARY", "Tertiary"
    QUATERNARY = "QUATERNARY", "Quaternary"
    QUINARY = "QUINARY", "Quinary"
    SENARY = "SENARY", "Senary"
    SEPTENARY = "SEPTENARY", "Septenary"
    OCTONARY = "OCTONARY", "Octonary"
    NONARY = "NONARY", "Nonary"
    DENARY = "DENARY", "Denary"
    UNDENARY = "UNDENARY", "Undenary"
    DUODENARY = "DUODENARY", "Duodenary"
    TREDENARY = "TREDENARY", "Tredenary"
    QUATTUORDENARY = "QUATTUORDENARY", "Quattuordenary"
    QUINDENARY = "QUINDENARY", "Quindenary"
    SEXDENARY = "SEXDENARY", "Sexdenary"
    SEPTENDENARY = "SEPTENDENARY", "Septendenary"
    OCTODENARY = "OCTODENARY", "Octodenary"
    NOVEMDENARY = "NOVEMDENARY", "Novemdenary"
    VIGINTENARY = "VIGINTENARY", "Vigintenary"


HANGING_PROTOCOL_SCHEMA = {
    "definitions": {},
    "$schema": "http://json-schema.org/draft-06/schema#",
    "title": "The Hanging Protocol Schema",
    "type": "array",
    "contains": {
        "type": "object",
        "properties": {
            "viewport_name": {
                "type": "string",
                "pattern": "^main$",
            },
        },
    },
    "items": {
        "type": "object",
        "title": "The Layout Object Schema",
        "required": ["viewport_name"],
        "properties": {
            "viewport_name": {
                "type": "string",
                "enum": [port.lower() for port in ImagePort.labels],
            },
            "x": {
                "type": "integer",
            },
            "y": {
                "type": "integer",
            },
            "w": {
                "type": "integer",
            },
            "h": {
                "type": "integer",
            },
            "fullsizable": {
                "type": "boolean",
            },
            "draggable": {
                "type": "boolean",
            },
            "selectable": {
                "type": "boolean",
            },
            "order": {
                "type": "integer",
            },
            "show_current_slice": {
                "type": "boolean",
            },
            "show_mouse_coordinate": {
                "type": "boolean",
            },
            "show_mouse_voxel_value": {
                "type": "boolean",
            },
            "label": {
                "type": "string",
            },
            "parent_id": {
                "type": "string",
                "enum": [port.lower() for port in ImagePort.labels],
            },
            "opacity": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
            },
        },
        "additionalProperties": False,
    },
    "minItems": 1,
    "uniqueItems": True,
}


VIEW_CONTENT_SCHEMA = {
    "definitions": {},
    "$schema": "http://json-schema.org/draft-06/schema#",
    "title": "The Display Port Mapping Schema",
    "type": "object",
    "properties": {
        port.lower(): {
            "type": "array",
            "contains": {"type": "string"},
            "minItems": 1,
            "uniqueItems": True,
        }
        for port in ImagePort.labels
    },
    "additionalProperties": False,
}


class HangingProtocol(UUIDModel, TitleSlugDescriptionModel):
    creator = models.ForeignKey(
        get_user_model(), null=True, on_delete=models.SET_NULL
    )
    json = models.JSONField(
        blank=False,
        validators=[JSONValidator(schema=HANGING_PROTOCOL_SCHEMA)],
    )

    class Meta(TitleSlugDescriptionModel.Meta, UUIDModel.Meta):
        ordering = ("title",)

    def __str__(self):
        return f"{self.title} (created by {self.creator})"

    def save(self, *args, **kwargs):
        adding = self._state.adding

        super().save(*args, **kwargs)

        if adding and self.creator:
            assign_perm(
                f"{self._meta.app_label}.change_{self._meta.model_name}",
                self.creator,
                self,
            )


class ViewContentMixin(models.Model):
    view_content = models.JSONField(
        blank=True,
        default=dict,
        validators=[JSONValidator(schema=VIEW_CONTENT_SCHEMA)],
    )

    class Meta:
        abstract = True

from django.contrib.auth import get_user_model
from django.db import models
from guardian.shortcuts import assign_perm

from grandchallenge.core.models import TitleSlugDescriptionModel, UUIDModel
from grandchallenge.core.validators import JSONValidator


class ImagePort(models.TextChoices):
    MAIN = "M", "Main"
    SECONDARY = "S", "Secondary"
    TERTIARY = "TERTIARY", "Tertiary"
    QUATERNARY = "QUATERNARY", "Quaternary"
    QUINARY = "QUINARY", "Quinary"
    SENARY = "SENARY", "Senary"
    SEPTENARY = "SEPTENARY", "Septenary"
    OCTONARY = "OCTONARY", "Octonary"
    NONARY = "NONARY", "Nonary"
    DENARY = "DENARY", "Denary"
    UNDENARY = "UNDENARY", "Undenary"
    DUODENARY = "DUODENARY", "Duodenary"
    TREDENARY = "TREDENARY", "Tredenary"
    QUATTUORDENARY = "QUATTUORDENARY", "Quattuordenary"
    QUINDENARY = "QUINDENARY", "Quindenary"
    SEXDENARY = "SEXDENARY", "Sexdenary"
    SEPTENDENARY = "SEPTENDENARY", "Septendenary"
    OCTODENARY = "OCTODENARY", "Octodenary"
    NOVEMDENARY = "NOVEMDENARY", "Novemdenary"
    VIGINTENARY = "VIGINTENARY", "Vigintenary"


HANGING_PROTOCOL_SCHEMA = {
    "definitions": {},
    "$schema": "http://json-schema.org/draft-06/schema#",
    "title": "The Hanging Protocol Schema",
    "type": "array",
    "contains": {
        "type": "object",
        "properties": {
            "viewport_name": {
                "type": "string",
                "pattern": "^main$",
            },
        },
    },
    "items": {
        "type": "object",
        "title": "The Layout Object Schema",
        "required": ["viewport_name"],
        "properties": {
            "viewport_name": {
                "type": "string",
                "enum": [port.lower() for port in ImagePort.labels],
            },
            "x": {
                "type": "integer",
            },
            "y": {
                "type": "integer",
            },
            "w": {
                "type": "integer",
            },
            "h": {
                "type": "integer",
            },
            "fullsizable": {
                "type": "boolean",
            },
            "draggable": {
                "type": "boolean",
            },
            "selectable": {
                "type": "boolean",
            },
            "order": {
                "type": "integer",
            },
            "show_current_slice": {
                "type": "boolean",
            },
            "show_mouse_coordinate": {
                "type": "boolean",
            },
            "show_mouse_voxel_value": {
                "type": "boolean",
            },
            "label": {
                "type": "string",
            },
            "parent_id": {
                "type": "string",
                "enum": [port.lower() for port in ImagePort.labels],
            },
            "opacity": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
            },
        },
        "additionalProperties": False,
    },
    "minItems": 1,
    "uniqueItems": True,
}


VIEW_CONTENT_SCHEMA = {
    "definitions": {},
    "$schema": "http://json-schema.org/draft-06/schema#",
    "title": "The Display Port Mapping Schema",
    "type": "object",
    "properties": {
        port.lower(): {
            "type": "array",
            "contains": {"type": "string"},
            "minItems": 1,
            "uniqueItems": True,
        }
        for port in ImagePort.labels
    },
    "additionalProperties": False,
}


class HangingProtocol(UUIDModel, TitleSlugDescriptionModel):
    creator = models.ForeignKey(
        get_user_model(), null=True, on_delete=models.SET_NULL
    )
    json = models.JSONField(
        blank=False,
        validators=[JSONValidator(schema=HANGING_PROTOCOL_SCHEMA)],
    )

    class Meta(TitleSlugDescriptionModel.Meta, UUIDModel.Meta):
        ordering = ("title",)

    def __str__(self):
        return f"{self.title} (created by {self.creator})"

    def save(self, *args, **kwargs):
        adding = self._state.adding

        super().save(*args, **kwargs)

        if adding and self.creator:
            assign_perm(
                f"{self._meta.app_label}.change_{self._meta.model_name}",
                self.creator,
                self,
            )


class ViewContentMixin(models.Model):
    view_content = models.JSONField(
        blank=True,
        default=dict,
        validators=[JSONValidator(schema=VIEW_CONTENT_SCHEMA)],
    )

    class Meta:
        abstract = True
