"""Character style definitions with derivation formulas.

Defines all character styles from the ODF/OOXML canonical set.
Each style includes properties derived from RecipeInputs.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Optional, TYPE_CHECKING

from tokenmoulds.dtcg.types import (
    Token,
    TokenExtensions,
    TokenGroup,
    TokenType,
)

if TYPE_CHECKING:
    from tokenmoulds.dtcg.recipe import RecipeInputs


@dataclass
class CharacterStyleDef:
    """Definition of a character style."""

    name: str  # Canonical name
    description: str
    ooxml_id: str  # Word styleId
    odf_name: str  # ODF style:name

    # Typography
    font_family: Optional[str] = None  # None means inherit from paragraph
    font_size_formula: Optional[str] = None  # None means inherit
    font_weight: Optional[int] = None
    font_style: Optional[str] = None  # normal, italic

    # Decoration
    underline: Optional[str] = None  # none, single, double, dotted, dashed
    strikethrough: bool = False

    # Color
    color_formula: Optional[str] = None
    background_formula: Optional[str] = None

    # Position
    position: Optional[str] = None  # superscript, subscript, normal

    # Parent style
    based_on: Optional[str] = None


# =============================================================================
# NOTE REFERENCE STYLES
# =============================================================================

NOTE_REFERENCE_STYLES = [
    CharacterStyleDef(
        name="FootnoteReference",
        description="Footnote reference mark (superscript number)",
        ooxml_id="FootnoteReference",
        odf_name="Footnote anchor",
        position="superscript",
        font_size_formula="{typography.scale.xs}",
    ),
    CharacterStyleDef(
        name="EndnoteReference",
        description="Endnote reference mark",
        ooxml_id="EndnoteReference",
        odf_name="Endnote anchor",
        position="superscript",
        font_size_formula="{typography.scale.xs}",
    ),
    CharacterStyleDef(
        name="CommentReference",
        description="Comment reference mark",
        ooxml_id="CommentReference",
        odf_name="Comment",
        font_size_formula="{typography.scale.xs}",
        color_formula="{color.ui.warning}",
    ),
]


# =============================================================================
# EMPHASIS STYLES
# =============================================================================

EMPHASIS_STYLES = [
    CharacterStyleDef(
        name="Emphasis",
        description="Emphasized text (italic)",
        ooxml_id="Emphasis",
        odf_name="Emphasis",
        font_style="italic",
    ),
    CharacterStyleDef(
        name="Strong",
        description="Strong emphasis (bold)",
        ooxml_id="Strong",
        odf_name="Strong Emphasis",
        font_weight=700,
    ),
    CharacterStyleDef(
        name="IntenseEmphasis",
        description="Intense emphasis (bold + color)",
        ooxml_id="IntenseEmphasis",
        odf_name="Intense Emphasis",
        font_weight=700,
        font_style="italic",
        color_formula="{color.brand.primary}",
    ),
    CharacterStyleDef(
        name="SubtleEmphasis",
        description="Subtle emphasis (italic + muted)",
        ooxml_id="SubtleEmphasis",
        odf_name="Subtle Emphasis",
        font_style="italic",
        color_formula="{color.text.muted}",
    ),
    CharacterStyleDef(
        name="IntenseReference",
        description="Intense reference style",
        ooxml_id="IntenseReference",
        odf_name="Intense Reference",
        font_weight=700,
        color_formula="{color.brand.primary}",
        underline="single",
    ),
    CharacterStyleDef(
        name="SubtleReference",
        description="Subtle reference style",
        ooxml_id="SubtleReference",
        odf_name="Subtle Reference",
        underline="single",
        color_formula="{color.text.muted}",
    ),
    CharacterStyleDef(
        name="BookTitle",
        description="Book title formatting",
        ooxml_id="BookTitle",
        odf_name="Book Title",
        font_style="italic",
    ),
]


# =============================================================================
# HYPERLINK STYLES
# =============================================================================

HYPERLINK_STYLES = [
    CharacterStyleDef(
        name="Hyperlink",
        description="Unvisited hyperlink",
        ooxml_id="Hyperlink",
        odf_name="Internet link",
        color_formula="{color.brand.secondary}",
        underline="single",
    ),
    CharacterStyleDef(
        name="FollowedHyperlink",
        description="Visited hyperlink",
        ooxml_id="FollowedHyperlink",
        odf_name="Visited Internet Link",
        color_formula="{color.text.muted}",
        underline="single",
    ),
    CharacterStyleDef(
        name="UnresolvedMention",
        description="Unresolved @mention",
        ooxml_id="UnresolvedMention",
        odf_name="Unresolved Mention",
        color_formula="{color.brand.secondary}",
        background_formula="{color.ui.highlight}",
    ),
]


# =============================================================================
# CODE AND TECHNICAL STYLES
# =============================================================================

CODE_STYLES = [
    CharacterStyleDef(
        name="Code",
        description="Inline code",
        ooxml_id="HTMLCode",
        odf_name="Source Text",
        font_family="monospace",
        font_size_formula="{typography.scale.sm}",
        background_formula="{color.ui.surface}",
    ),
    CharacterStyleDef(
        name="CodeSample",
        description="Code sample text",
        ooxml_id="HTMLSample",
        odf_name="Sample",
        font_family="monospace",
        font_size_formula="{typography.scale.sm}",
    ),
    CharacterStyleDef(
        name="KeyboardShortcut",
        description="Keyboard shortcut text",
        ooxml_id="HTMLKeyboard",
        odf_name="Keyboard",
        font_family="monospace",
        font_size_formula="{typography.scale.sm}",
        background_formula="{color.ui.surface}",
    ),
    CharacterStyleDef(
        name="Variable",
        description="Variable name (technical)",
        ooxml_id="HTMLVariable",
        odf_name="Variable",
        font_family="monospace",
        font_style="italic",
    ),
    CharacterStyleDef(
        name="Definition",
        description="Definition instance",
        ooxml_id="HTMLDefinition",
        odf_name="Definition",
        font_style="italic",
    ),
    CharacterStyleDef(
        name="Teletype",
        description="Teletype/typewriter text",
        ooxml_id="HTMLTypewriter",
        odf_name="Teletype",
        font_family="monospace",
    ),
]


# =============================================================================
# CITATION STYLES
# =============================================================================

CITATION_STYLES = [
    CharacterStyleDef(
        name="Citation",
        description="Citation/quote attribution",
        ooxml_id="HTMLCite",
        odf_name="Citation",
        font_style="italic",
    ),
    CharacterStyleDef(
        name="QuoteChar",
        description="Inline quote character style",
        ooxml_id="QuoteChar",
        odf_name="Quotation",
        font_style="italic",
        color_formula="{color.text.muted}",
    ),
]


# =============================================================================
# LIST AND NUMBERING STYLES
# =============================================================================

LIST_CHARACTER_STYLES = [
    CharacterStyleDef(
        name="NumberingSymbols",
        description="Numbering symbols (1., 2., etc.)",
        ooxml_id="ListLabel",
        odf_name="Numbering Symbols",
        font_weight=600,
    ),
    CharacterStyleDef(
        name="BulletSymbols",
        description="Bullet symbols",
        ooxml_id="BulletLabel",
        odf_name="Bullet Symbols",
    ),
]


# =============================================================================
# FIELD AND REFERENCE STYLES
# =============================================================================

FIELD_STYLES = [
    CharacterStyleDef(
        name="PageNumber",
        description="Page number field",
        ooxml_id="PageNumber",
        odf_name="Page Number",
    ),
    CharacterStyleDef(
        name="LineNumber",
        description="Line number",
        ooxml_id="LineNumber",
        odf_name="Line numbering",
        font_size_formula="{typography.scale.xs}",
        color_formula="{color.text.muted}",
    ),
    CharacterStyleDef(
        name="Placeholder",
        description="Placeholder text (Click here...)",
        ooxml_id="PlaceholderText",
        odf_name="Placeholder",
        color_formula="{color.text.muted}",
        font_style="italic",
    ),
    CharacterStyleDef(
        name="IndexLink",
        description="Index jump link",
        ooxml_id="IndexLink",
        odf_name="Index Link",
        color_formula="{color.brand.secondary}",
    ),
    CharacterStyleDef(
        name="MainIndexEntry",
        description="Main entry in index (bold)",
        ooxml_id="MainIndexEntry",
        odf_name="Main index entry",
        font_weight=700,
    ),
]


# =============================================================================
# DROP CAP AND SPECIAL STYLES
# =============================================================================

SPECIAL_CHARACTER_STYLES = [
    CharacterStyleDef(
        name="DropCap",
        description="Drop cap letter",
        ooxml_id="DropCap",
        odf_name="Drop Caps",
        font_size_formula="{typography.scale.4xl}",
        font_weight=700,
        color_formula="{color.brand.primary}",
    ),
    CharacterStyleDef(
        name="RubyText",
        description="Ruby annotation text (Asian typography)",
        ooxml_id="RubyText",
        odf_name="Rubies",
        font_size_formula="{typography.scale.xs}",
    ),
    CharacterStyleDef(
        name="VerticalNumbering",
        description="Vertical numbering symbols",
        ooxml_id="VerticalNumbering",
        odf_name="Vert. Numbering Symbols",
    ),
]


# =============================================================================
# ALL CHARACTER STYLES
# =============================================================================

ALL_CHARACTER_STYLES = (
    NOTE_REFERENCE_STYLES
    + EMPHASIS_STYLES
    + HYPERLINK_STYLES
    + CODE_STYLES
    + CITATION_STYLES
    + LIST_CHARACTER_STYLES
    + FIELD_STYLES
    + SPECIAL_CHARACTER_STYLES
)


def build_character_styles(inputs: RecipeInputs) -> TokenGroup:
    """Build character style tokens from inputs.

    Args:
        inputs: Recipe inputs for derivation

    Returns:
        TokenGroup containing all character styles
    """
    group = TokenGroup(
        name="character",
        description="Character styles - emphasis, links, code, etc.",
    )

    for style_def in ALL_CHARACTER_STYLES:
        style_group = _build_style_token(style_def, inputs)
        group.groups[style_def.name] = style_group

    return group


def _build_style_token(
    style_def: CharacterStyleDef, inputs: RecipeInputs
) -> TokenGroup:
    """Build a single character style as a TokenGroup."""
    style = TokenGroup(
        name=style_def.name,
        description=style_def.description,
    )

    # OOXML/ODF mapping
    style.tokens["ooxmlId"] = Token(
        name="ooxmlId",
        value=style_def.ooxml_id,
        description="Word styleId",
    )
    style.tokens["odfName"] = Token(
        name="odfName",
        value=style_def.odf_name,
        description="ODF style:name",
    )

    # Font family (only if specified - None means inherit)
    if style_def.font_family is not None:
        style.tokens["fontFamily"] = Token(
            name="fontFamily",
            value=style_def.font_family,
            type=TokenType.FONT_FAMILY,
        )

    # Font size (with formula) - only if specified
    if style_def.font_size_formula is not None:
        style.tokens["fontSize"] = Token(
            name="fontSize",
            value=style_def.font_size_formula,
            type=TokenType.DIMENSION,
            extensions=TokenExtensions(
                derivation_formula=style_def.font_size_formula,
                derivation_source="formula",
            ),
        )

    # Font weight - only if specified
    if style_def.font_weight is not None:
        style.tokens["fontWeight"] = Token(
            name="fontWeight",
            value=style_def.font_weight,
            type=TokenType.FONT_WEIGHT,
        )

    # Font style - only if specified
    if style_def.font_style is not None:
        style.tokens["fontStyle"] = Token(
            name="fontStyle",
            value=style_def.font_style,
        )

    # Underline
    if style_def.underline is not None:
        style.tokens["underline"] = Token(
            name="underline",
            value=style_def.underline,
        )

    # Strikethrough
    if style_def.strikethrough:
        style.tokens["strikethrough"] = Token(
            name="strikethrough",
            value=1,
            type=TokenType.NUMBER,
        )

    # Color
    if style_def.color_formula is not None:
        style.tokens["color"] = Token(
            name="color",
            value=style_def.color_formula,
            type=TokenType.COLOR,
            extensions=TokenExtensions(
                derivation_formula=style_def.color_formula,
                derivation_source="formula",
            ),
        )

    # Background color
    if style_def.background_formula is not None:
        style.tokens["background"] = Token(
            name="background",
            value=style_def.background_formula,
            type=TokenType.COLOR,
            extensions=TokenExtensions(
                derivation_formula=style_def.background_formula,
                derivation_source="formula",
            ),
        )

    # Position (superscript/subscript)
    if style_def.position is not None:
        style.tokens["position"] = Token(
            name="position",
            value=style_def.position,
        )

    # Inheritance
    if style_def.based_on:
        style.tokens["basedOn"] = Token(
            name="basedOn",
            value=f"{{styles.character.{style_def.based_on}.ooxmlId}}",
            description="Parent style",
        )

    return style
