from pydantic import BaseModel, Field
from typing import Dict, List, Optional

from nsj_rest_lib2.compiler.edl_model.property_meta_model import PropertyMetaModel
from nsj_rest_lib2.compiler.edl_model.repository_model import RepositoryModel
from nsj_rest_lib2.compiler.edl_model.api_model import APIModel
from nsj_rest_lib2.compiler.edl_model.trait_property_meta_model import (
    TraitPropertyMetaModel,
)


class EntityModel(BaseModel):
    edl_version: Optional[str] = Field(default="1.0", description="Versão do EDL")
    escopo: str = Field(..., description="Escopo do EDL (define a aplicação).")
    description: str = Field(..., description="Descrição da entidade.")
    id: str = Field(
        ...,
        description="Identificador único da entidade, dentro de um determinado escopo (podendo ser sobreescrito para um tenant ou grupo _empresarial).",
    )
    trait_from: Optional[str] = Field(
        None, description="Identificador da entidade que a trait estende."
    )
    version: Optional[str] = Field(
        default="1.0", description="Versão da entidade (padrão: 1.0)."
    )
    abstract: Optional[bool] = Field(
        default=False,
        description="Indica se a entidade é abstrata (padrão: False). Caso positivo, não gera código, mas pode ser usada na geração de código de outras entidades.",
    )
    mixins: Optional[List[str]] = Field(
        None,
        description="Lista de mixins (blocos reutilizáveis) aplicados ao modelo.",
    )
    required: Optional[List[str]] = Field(
        None, description="Lista de campos obrigatórios no modelo."
    )
    partition_data: Optional[List[str]] = Field(
        None,
        description="Lista de propriedades da entidade, que serã usadas para particionamento dos dados no banco (sendo obrigatórias em todas as chamadas, inclusive como um tipo de filtro obrigatório).",
    )
    main_properties: Optional[List[str]] = Field(
        None,
        description="Lista de propriedades resumo do modelo (retornadas em qualquer chamada GET, mesmo que não pedidas por meio do parâmetro 'fields').",
    )
    search_properties: Optional[List[str]] = Field(
        None,
        description="Lista de propriedades do modelo que serão utilizadas nas chamadas de query do usuário (suportando também campos das entidades relacionadas). Sugere-se que a biblioteca crie automaticamente os índices para fulltext search.",
    )
    metric_label: Optional[List[str]] = Field(
        None,
        description="Lista de campos incluídos no agrupamento das métricas enviadas ao OpenTelemetry.",
    )
    trait_properties: Optional[Dict[str, TraitPropertyMetaModel]] = Field(
        None,
        description="Dicionário de propriedades condicionais da trait (isso é, especifica propriedades, e seus valores fixos, que serão usados como um tipo de filtro fixo usado como condição para que a propridade principal assum o papel daquele tipo de trait).",
    )
    properties: Dict[str, PropertyMetaModel] = Field(
        ..., description="Dicionário de propriedades do modelo."
    )
    repository: RepositoryModel = Field(
        ..., description="Configurações de mapeamento para o banco de dados."
    )
    api: APIModel = Field(
        ...,
        description="Definição da API REST associada ao modelo, com todos os seus endpoints.",
    )
