# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Configuration for Moondream3 model."""

from transformers import PretrainedConfig


class Moondream3VisionConfig(PretrainedConfig):
    """Vision encoder configuration for Moondream3."""

    model_type = "moondream3_vision"

    def __init__(
        self,
        enc_dim: int = 1152,
        enc_patch_size: int = 14,
        enc_n_layers: int = 27,
        enc_ff_dim: int = 4304,
        enc_n_heads: int = 16,
        proj_inner_dim: int = 8192,
        crop_size: int = 378,
        max_crops: int = 12,
        overlap_margin: int = 4,
        **kwargs,
    ):
        super().__init__(**kwargs)
        self.enc_dim = enc_dim
        self.enc_patch_size = enc_patch_size
        self.enc_n_layers = enc_n_layers
        self.enc_ff_dim = enc_ff_dim
        self.enc_n_heads = enc_n_heads
        self.proj_inner_dim = proj_inner_dim
        self.crop_size = crop_size
        self.max_crops = max_crops
        self.overlap_margin = overlap_margin

        # Standard HuggingFace attributes for vision config
        self.hidden_size = enc_dim
        self.num_attention_heads = enc_n_heads
        self.num_hidden_layers = enc_n_layers
        self.intermediate_size = enc_ff_dim
        self.patch_size = enc_patch_size
        self.image_size = crop_size


class Moondream3TextConfig(PretrainedConfig):
    """Text decoder configuration for Moondream3."""

    model_type = "moondream3_text"

    def __init__(
        self,
        dim: int = 2048,
        ff_dim: int = 8192,
        n_layers: int = 24,
        vocab_size: int = 51200,
        max_context: int = 4096,
        n_heads: int = 32,
        n_kv_heads: int = 32,
        prefix_attn: int = 730,
        rope_theta: float = 1500000.0,
        moe: dict | None = None,
        **kwargs,
    ):
        super().__init__(**kwargs)

        # Store original moondream3 config names
        self.dim = dim
        self.ff_dim = ff_dim
        self.n_layers = n_layers
        self.n_heads = n_heads
        self.n_kv_heads = n_kv_heads
        self.prefix_attn = prefix_attn
        self.max_context = max_context
        self.rope_theta = rope_theta

        # MoE config
        moe = moe or {}
        self.moe_start_layer = moe.get("start_layer", 4)
        self.moe_num_experts = moe.get("n_experts", 64)
        self.moe_experts_per_token = moe.get("n_experts_per_tok", 8)
        self.moe_expert_inner_dim = moe.get("expert_inner_dim", 1024)

        # Standard HuggingFace attributes (required by vLLM)
        self.hidden_size = dim
        self.num_attention_heads = n_heads
        self.num_key_value_heads = n_kv_heads
        self.num_hidden_layers = n_layers
        self.intermediate_size = ff_dim
        self.vocab_size = vocab_size
        self.max_position_embeddings = max_context

        # Moondream3 uses token 0 (<|endoftext|>) as both BOS and EOS.
        # Token 3 (<|md_reserved_2|>) is an answer delimiter that the model
        # implementation suppresses during generation.
        self.bos_token_id = 0
        self.eos_token_id = 0

        # MoE standard attributes
        self.num_local_experts = self.moe_num_experts
        self.num_experts_per_tok = self.moe_experts_per_token


class Moondream3Config(PretrainedConfig):
    """Combined configuration for Moondream3 multimodal model."""

    model_type = "moondream3"
    is_composition = True

    def __init__(
        self,
        config: dict | None = None,
        **kwargs,
    ):
        config = config or {}

        # Parse text config
        text_config = config.get("text", {})
        self.text_config: Moondream3TextConfig = Moondream3TextConfig(**text_config)

        # Parse vision config
        vision_config = config.get("vision", {})
        self.vision_config = Moondream3VisionConfig(**vision_config)

        # Store the original config dict for model access
        self.config = config
        tokenizer_config = config.get("tokenizer", {})
        self.answer_token_id = tokenizer_config.get("answer_id", 3)

        super().__init__(**kwargs)

        # Expose key attributes at top level for vLLM compatibility
        self.hidden_size = self.text_config.hidden_size
        self.num_attention_heads = self.text_config.num_attention_heads
        self.num_key_value_heads = self.text_config.num_key_value_heads
        self.num_hidden_layers = self.text_config.num_hidden_layers
        self.vocab_size = self.text_config.vocab_size
        self.intermediate_size = self.text_config.intermediate_size

        # Moondream3 uses token 0 (<|endoftext|>) as both BOS and EOS.
        # Token 3 (<|md_reserved_2|>) is an answer delimiter that the model
        # implementation suppresses during generation.
        self.bos_token_id = 0
        self.eos_token_id = 0

    def get_text_config(self, decoder: bool = False) -> "Moondream3TextConfig":
        """Return the text config for vLLM's text_config detection.

        Args:
            decoder: Ignored. Only used for encoder-decoder models.
        """
        return self.text_config
