# generated by datamodel-codegen:
#   filename:  Application.json

from __future__ import annotations

from enum import Enum
from typing import Any, Literal, Optional, Union

from pydantic import BaseModel, ConfigDict, Field, conint, constr


class Status(Enum):
    pending = 'pending'
    in_progress = 'in-progress'
    done = 'done'
    blocked = 'blocked'


class TodoItem(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    description: str
    status: Status
    owner: Optional[str] = None
    tags: Optional[list[str]] = None
    link: Optional[str] = None


class Metadata(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    name: str = Field(..., description="Application identifier (e.g., 'video-platform', 'crm-app')")
    intent: Optional[str] = Field(
        None, description='Human-readable description of application purpose'
    )
    version: Optional[str] = Field(None, description="Semantic version (e.g., '1.0.0')")
    todo: Optional[list[TodoItem]] = None


class Resources(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    type: Literal['PostgresDB']
    connection_string: str


class Resources1(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    type: Literal['ObjectStore']
    endpoint_url: str
    bucket: str
    access_key: str
    secret_key: str
    region: Optional[str] = None


class Resources2(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    type: Literal['VectorDB']
    provider: str
    api_key: str
    environment: Optional[str] = None
    index_name: Optional[str] = None


class SecretProviders(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    default: Optional[str] = None
    providers: Optional[dict[str, Any]] = None


class Contract(BaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    env_file: Optional[str] = Field(None, description="Path to environment file (e.g., '.env')")
    env_files: Optional[list[str]] = Field(None, description='Array of environment file paths')
    resources: Optional[list[Union[Resources, Resources1, Resources2]]] = Field(
        None, description='External resources (databases, APIs, storage) this application requires'
    )
    secret_providers: Optional[SecretProviders] = Field(
        None, description='Secret management configuration (Vault, AWS Secrets Manager, etc.)'
    )


class Kind(Enum):
    DataAsset = 'DataAsset'
    Event = 'Event'
    Component = 'Component'


class Stability(Enum):
    stable = 'stable'
    beta = 'beta'
    experimental = 'experimental'


class Deprecation(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    notice: Optional[str] = None
    sunset_date: Optional[str] = None


class Export(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    kind: Kind = Field(..., description='Type of export')
    path: str = Field(
        ..., description="Path to exported definition (e.g., './events/user-created')"
    )
    stability: Optional[Stability] = Field(None, description='API stability level')
    description: Optional[str] = None
    schema_version: Optional[str] = None
    deprecation: Optional[Deprecation] = None


class Requires(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    features: Optional[list[str]] = Field(
        None, description="Required platform features (e.g., 'gpu', 'redis')"
    )
    minimum_platform: Optional[str] = Field(None, description='Minimum Knot0 platform version')


class ProvisionedInfraItem(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    name: str = Field(..., description="Logical infrastructure name (e.g., 'postgres', 'redis')")
    uses: constr(pattern=r'^(library://|\.{1,2}/).+')
    environment: Optional[str] = None
    inputs: Optional[dict[str, Any]] = None
    depends_on: Optional[list[str]] = None


class Test(BaseModel):
    model_config = ConfigDict(
        extra='allow',
    )
    scenario: str
    run: Optional[str] = None
    with_: Optional[dict[str, Any]] = Field(None, alias='with')
    expect: Optional[list[str]] = None
    timeout_seconds: Optional[conint(ge=1)] = Field(
        None, description='Optional per-scenario timeout in seconds'
    )
    services: Optional[list[str]] = Field(
        None, description="Logical services this test exercises (e.g. ['users','orders'])"
    )


class Serve(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    entry_service: Optional[str] = Field(
        None,
        description="Name of the service that should be exposed at the root '/' entrypoint (e.g., 'web', 'frontend')",
    )


class Trigger(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    event: constr(pattern=r'^[a-z0-9]+(?:\.[a-z0-9]+)*$') = Field(
        ...,
        description="Event name that triggers this worker (lowercase dot-notation: 'video.uploaded', 'user.created')",
    )
    uses: constr(pattern=r'^(\./)?processes/[a-z0-9][a-z0-9_-]{0,63}$') = Field(
        ..., description="Path to worker process (e.g., './processes/transcode-worker')"
    )
    filters: Optional[list[str]] = Field(
        None, description='Optional filters to match specific event payloads'
    )


class Statechart(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    initial: Optional[str] = Field(None, description='Initial state name')
    context: Optional[dict[str, Any]] = Field(
        None, description='Global context available to all states'
    )
    triggers: Optional[list[Trigger]] = Field(
        None,
        description='Optional documentation for workspace-level triggers. Actual worker launch behaviour comes from process state machines.',
    )
    states: Optional[dict[str, Any]] = Field(
        None, description='Application-level state machine states'
    )


class Serve1(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    entry: Optional[bool] = Field(
        None, description="If true, this service handles requests at root '/' path"
    )
    health_path: Optional[str] = Field(
        None, description="Health check endpoint path (e.g., '/health', '/api/health')"
    )


class Port(BaseModel):
    port: int = Field(..., description='Container port (e.g., 80, 8000, 3000)')
    path_prefix: str = Field(
        ..., description="Public URL path prefix (e.g., '/', '/api', '/admin')"
    )


class Service(BaseModel):
    name: str = Field(..., description="Service identifier (e.g., 'web', 'api', 'worker')")
    uses: constr(pattern=r'^(\./)?processes/[a-z0-9][a-z0-9_-]{0,63}$')
    serve: Optional[Serve1] = Field(None, description='Web serving configuration for this service')
    ports: list[Port] = Field(..., description='Network ports and routing configuration')


class Job(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    name: str = Field(
        ..., description="Job identifier (e.g., 'database-migration', 'daily-report')"
    )
    uses: constr(pattern=r'^(\./)?processes/[a-z0-9][a-z0-9_-]{0,63}$')


class Body(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    serve: Optional[Serve] = Field(
        None, description='Web serving configuration for public-facing services'
    )
    statechart: Optional[Statechart] = Field(
        None,
        description='Application-level state machine used for documentation or orchestration policies. Runtime trigger wiring is derived from individual process manifests.',
    )
    services: Optional[list[Service]] = Field(
        None,
        description='Long-running persistent services (web servers, APIs, databases) - MUST be an array',
    )
    jobs: Optional[list[Job]] = Field(
        None, description='One-time or scheduled job processes (NOT event-triggered)'
    )


class Profiles(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    cpu: Optional[str] = Field(None, description="CPU allocation (e.g., '1.0', '0.5')")
    memory: Optional[str] = Field(None, description="Memory allocation (e.g., '512Mi', '2Gi')")
    disk: Optional[str] = Field(None, description="Disk allocation (e.g., '10Gi')")


class GpuProfiles(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    accelerator: Optional[str] = Field(None, description="GPU type (e.g., 'nvidia-tesla-t4')")
    cpu: Optional[str] = None
    memory: Optional[str] = None
    gpu_memory: Optional[str] = Field(None, description='GPU memory allocation')


class Compute(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    profiles: Optional[dict[str, Profiles]] = Field(
        None, description='CPU/memory profiles for different service types'
    )
    gpu_profiles: Optional[dict[str, GpuProfiles]] = Field(
        None, description='GPU-accelerated profiles for ML/AI workloads'
    )


class Application(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    kind: Literal['Application']
    schema_version: str
    metadata: Metadata
    contract: Optional[Contract] = None
    exports: Optional[list[Export]] = Field(
        None, description='Public API surface - events, data types, and components this app exposes'
    )
    requires: Optional[Requires] = Field(
        None, description='Platform capabilities and minimum versions required'
    )
    provisioned_infra: Optional[list[ProvisionedInfraItem]] = Field(
        None,
        description='Infrastructure components to provision (databases, message queues, caches)',
    )
    tests: Optional[list[Test]] = Field(None, description='Application-level integration tests')
    body: Optional[Body] = None
    compute: Optional[Compute] = Field(
        None, description='Resource allocation profiles for services'
    )
