from __future__ import annotations

from dataclasses import dataclass
from typing import Any

try:
    from . import generate_prompt_batches as g
    from . import pov_policy
    from . import row_camera as row_camera_policy
    from . import row_expression as row_expression_policy
    from . import row_rendering as row_rendering_policy
except ImportError:  # Allows local smoke tests from the repository root.
    import generate_prompt_batches as g
    import pov_policy
    import row_camera as row_camera_policy
    import row_expression as row_expression_policy
    import row_rendering as row_rendering_policy


@dataclass(frozen=True)
class CustomRowAssemblyRequest:
    row_number: int
    start_index: int
    category: dict[str, Any]
    subcategory: dict[str, Any]
    item: Any
    context: dict[str, Any]
    subject_type: str
    item_text: str
    item_name: str
    item_axis_values: dict[str, Any]
    item_template_metadata: dict[str, Any]
    formatter_hints: dict[str, Any]
    item_label: str
    style: str
    positive_suffix: str
    negative_prompt: str
    scene_slug: str
    scene: str
    scene_entry: dict[str, Any]
    pose: str
    expression: str
    shared_expression: str
    character_expressions: list[str]
    character_expression_text: str
    expression_disabled: bool
    expression_intensity: float | None
    expression_intensity_source: str
    composition: str
    source_composition: str
    composition_entry: dict[str, Any]
    role_graph: str
    source_role_graph: str
    action_family: str
    position_family: str
    position_key: str
    position_keys: list[str]
    pov_character_labels: list[str]
    cast_descriptors: list[str]
    cast_descriptor_text: str
    seed_config: dict[str, Any]
    hardcore_position_config: dict[str, Any] | None = None
    location_config: dict[str, Any] | None = None
    composition_config: dict[str, Any] | None = None
    content_seed_axis: str = "content"
    count_adjustment: dict[str, Any] | None = None
    applied_profile: dict[str, Any] | None = None
    profile_status: str = "none"
    applied_slot: dict[str, Any] | None = None
    slot_status: str = "none"
    character_slots: list[dict[str, Any]] | None = None


def assemble_custom_row(request: CustomRowAssemblyRequest) -> dict[str, Any]:
    r = request
    render_context = dict(r.context)
    pov_prompt_directive = pov_policy.pov_prompt_directive(r.pov_character_labels)
    render_context.update(
        {
            "trigger": g.TRIGGER,
            "main_category": r.category["name"],
            "subcategory": r.subcategory["name"],
            "category": r.category["name"],
            "item": r.item_text,
            "item_name": r.item_name,
            "item_label": r.item_label,
            "style": r.style,
            "scene": r.scene,
            "scene_slug": r.scene_slug,
            "scene_entry": r.scene_entry,
            "pose": r.pose,
            "expression": r.expression,
            "shared_expression": r.shared_expression,
            "character_expressions": r.character_expressions,
            "character_expression_text": r.character_expression_text,
            "expression_enabled": not r.expression_disabled,
            "expression_disabled": r.expression_disabled,
            "expression_intensity": r.expression_intensity,
            "expression_intensity_source": r.expression_intensity_source,
            "composition": r.composition,
            "composition_entry": r.composition_entry,
            "source_composition": r.source_composition,
            "composition_prompt": row_camera_policy.composition_prompt(r.composition),
            "composition_config": r.composition_config or {},
            "role_graph": r.role_graph,
            "source_role_graph": r.source_role_graph,
            "action_family": r.action_family,
            "position_family": r.position_family,
            "position_key": r.position_key,
            "position_keys": r.position_keys,
            "pov_character_labels": r.pov_character_labels,
            "pov_prompt_directive": pov_prompt_directive,
            "cast_descriptors": r.cast_descriptor_text,
            "positive_suffix": r.positive_suffix,
            "negative_prompt": r.negative_prompt,
        }
    )
    rendered = row_rendering_policy.render_prompt_caption(
        item=r.item,
        subcategory=r.subcategory,
        category=r.category,
        subject_type=r.subject_type,
        context=render_context,
        cast_descriptor_text=r.cast_descriptor_text,
        pov_prompt_directive=pov_prompt_directive if r.pov_character_labels else "",
    )
    batch = max(1, ((r.row_number - 1) // g.BATCH_SIZE) + 1)
    index = r.start_index + r.row_number - 1
    row = g.row_base(
        index,
        batch,
        render_context["subject"],
        render_context["age"],
        render_context["body"],
        r.scene_slug,
        r.composition,
    )
    row.update(
        {
            "prompt": rendered["prompt"],
            "caption": rendered["caption"],
            "negative_prompt": r.negative_prompt,
            "expression": r.expression,
            "main_category": r.category["name"],
            "subcategory": r.subcategory["name"],
            "category_slug": r.category["slug"],
            "subcategory_slug": r.subcategory["slug"],
            "subject_type": r.subject_type,
            "subject_phrase": render_context.get("subject_phrase", ""),
            "body_phrase": render_context.get("body_phrase", ""),
            "skin": render_context.get("skin", ""),
            "hair": render_context.get("hair", ""),
            "eyes": render_context.get("eyes", ""),
            "style": r.style,
            "item": r.item_text,
            "item_label": r.item_label,
            "positive_suffix": r.positive_suffix,
            "custom_item": r.item_name,
            "item_axis_values": r.item_axis_values,
            "item_template_metadata": r.item_template_metadata,
            "formatter_hints": r.formatter_hints,
            "scene_text": r.scene,
            "scene_entry": r.scene_entry,
            "location_theme": (r.location_config or {}).get("theme", ""),
            "scene_theme": r.scene_entry.get("theme", "") or (
                (r.location_config or {}).get("theme", "")
                if (r.location_config or {}).get("apply_mode") == "replace"
                else ""
            ),
            "location_config": r.location_config or {},
            "pose": r.pose,
            "seed_config": r.seed_config,
            "hardcore_position_config": r.hardcore_position_config or {},
            "content_seed_axis": r.content_seed_axis,
            "role_graph": r.role_graph,
            "source_role_graph": r.source_role_graph,
            "action_family": r.action_family,
            "position_family": r.position_family,
            "position_key": r.position_key,
            "position_keys": r.position_keys,
            "source_composition": r.source_composition,
            "composition_entry": r.composition_entry,
            "composition_theme": (r.composition_config or {}).get("theme", ""),
            "pov_character_labels": r.pov_character_labels,
            "pov_prompt_directive": pov_prompt_directive,
            "shared_expression": r.shared_expression,
            "character_expressions": r.character_expressions,
            "character_expression_text": r.character_expression_text,
            "expression_enabled": not r.expression_disabled,
            "expression_disabled": r.expression_disabled,
            "cast_summary": render_context.get("cast_summary", ""),
            "cast_descriptors": r.cast_descriptors,
            "cast_descriptor_text": r.cast_descriptor_text,
            "scene_kind": render_context.get("scene_kind", ""),
            "women_count": render_context.get("women_count", ""),
            "men_count": render_context.get("men_count", ""),
            "person_count": render_context.get("person_count", ""),
            "cast_count_adjustment": r.count_adjustment if r.subject_type == "configured_cast" else {},
            "character_profile": r.applied_profile or {},
            "character_profile_status": r.profile_status,
            "character_slot": r.applied_slot or {},
            "character_slot_status": r.slot_status,
            "character_cast_slots": r.character_slots or [],
            "expression_intensity": r.expression_intensity,
            "expression_intensity_source": r.expression_intensity_source,
            "source": "json_category",
        }
    )
    if render_context.get("figure"):
        row["figure"] = render_context["figure"]
    if r.expression_disabled:
        row = row_expression_policy.disable_row_expression(row, r.expression_intensity_source)
    return row
