from typing import Any
from sqlmodel import Field, SQLModel, MetaData, JSON, TEXT, Relationship, Column
from pydantic import computed_field

from .metadata import gisaf_survey

mapbox_type_mapping = {
    'Point': 'symbol',
    'Line': 'line',
    'Polygon': 'fill',
}

class CategoryGroup(SQLModel, table=True):
    metadata = gisaf_survey
    name: str = Field(min_length=4, max_length=4,
                      default=None, primary_key=True)
    major: str
    long_name: str

    class Admin:
        menu = 'Other'
        flask_admin_model_view = 'CategoryGroupModelView'


class CategoryModelType(SQLModel, table=True):
    metadata = gisaf_survey
    name: str = Field(default=None, primary_key=True)

    class Admin:
        menu = 'Other'
        flask_admin_model_view = 'MyModelViewWithPrimaryKey'


class CategoryBase(SQLModel):
    class Admin:
        menu = 'Other'
        flask_admin_model_view = 'CategoryModelView'

    name: str | None = Field(default=None, primary_key=True)
    description: str | None
    group: str = Field(min_length=4, max_length=4,
                       foreign_key="CategoryGroup.name", index=True)
    #group_: CategoryGroup = Relationship()
    minor_group_1: str = Field(min_length=4, max_length=4, default='----')
    minor_group_2: str = Field(min_length=4, max_length=4, default='----')
    status: str = Field(min_length=1, max_length=1)
    custom: bool | None
    auto_import: bool = True
    model_type: str = Field(max_length=50,
                            foreign_key='CategoryModelType.name',
                            default='Point')
    long_name: str | None = Field(max_length=50)
    style: str | None = Field(sa_column=Column(TEXT))
    symbol: str | None = Field(max_length=1)
    mapbox_type_custom: str | None = Field(max_length=32)
    mapbox_paint: dict[str, Any] | None = Field(sa_column=Column(JSON(none_as_null=True)))
    mapbox_layout: dict[str, Any] | None = Field(sa_column=Column(JSON(none_as_null=True)))
    viewable_role: str | None
    extra: dict[str, Any] | None = Field(sa_column=Column(JSON(none_as_null=True)))


class Category(CategoryBase, table=True):
    metadata = gisaf_survey
    name: str = Field(default=None, primary_key=True)


class CategoryRead(CategoryBase):
    name: str
    domain: str = 'V'  # Survey

    @computed_field
    @property
    def layer_name(self) -> str:
        """
        ISO compliant layer name (see ISO 13567)
        :return: str
        """
        return '{self.domain}-{self.group:4s}-{self.minor_group_1:4s}-{self.minor_group_2:4s}-{self.status:1s}'.format(self=self)

    @computed_field
    @property
    def table_name(self) -> str:
        """
        Table name
        :return:
        """
        if self.minor_group_2 == '----':
            return '{self.domain}_{self.group:4s}_{self.minor_group_1:4s}'.format(self=self)
        else:
            return '{self.domain}_{self.group:4s}_{self.minor_group_1:4s}_{self.minor_group_2:4s}'.format(self=self)

    @computed_field
    @property
    def raw_survey_table_name(self) -> str:
        """
        Table name
        :return:
        """
        if self.minor_group_2 == '----':
            return 'RAW_{self.domain}_{self.group:4s}_{self.minor_group_1:4s}'.format(self=self)
        else:
            return 'RAW_{self.domain}_{self.group:4s}_{self.minor_group_1:4s}_{self.minor_group_2:4s}'.format(self=self)

    @computed_field
    @property
    def mapbox_type(self) -> str:
        return self.mapbox_type_custom or mapbox_type_mapping[self.model_type]