"""数据模型模块。

定义换板打包器所用的全部数据类、类型别名和常量，包括：
- 板件任务 (PlateJob)
- G-code 补丁规则与配置 (GcodePatchRule / GcodePatchConfig)
- 构建选项 (BuildOptions)
- 板件来源与摘要 (PlateSource / ThreeMfSummary / BuildSummary)
- 构建结果 (BuildResult)
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import Literal

# 默认插入标记：在此行之前插入换板 G-code
DEFAULT_INSERT_BEFORE_MARKER = ";=====printer finish  sound========="
# 默认 ZIP 压缩级别 (0-9，7 为平衡选择)
DEFAULT_ZIP_COMPRESS_LEVEL = 7

# 元数据计算模式：取源文件数值还是累加求和
MetadataMode = Literal["source", "sum"]
# 换行符风格：LF (Unix) 或 CRLF (Windows)
LineEnding = Literal["lf", "crlf"]


@dataclass(frozen=True)
class PlateJob:
    """单个板件打包任务。

    Attributes:
        source_3mf: 源 3MF 文件路径。
        copies: 该板件的副本数量，默认为 1。
    """
    source_3mf: Path
    copies: int = 1


@dataclass(frozen=True)
class GcodePatchRule:
    """单条 G-code 查找替换规则。

    Attributes:
        name: 规则名称，用于识别和日志。
        find: 要查找的目标字符串。
        replace: 替换后的字符串。
        flag: 正则标志（可选），如 "i" 表示忽略大小写。
        enabled: 是否启用该规则，默认启用。
        max_count: 最大替换次数，默认 1（仅替换首次出现）。
    """
    name: str
    find: str
    replace: str
    flag: str = ""          # 正则标志，例如 'i' 表示忽略大小写
    enabled: bool = True    # 是否启用此规则
    max_count: int = 1      # 最多替换次数


@dataclass(frozen=True)
class GcodePatchConfig:
    """G-code 补丁配置，包含一组规则和插入标记。

    Attributes:
        rules: 补丁规则元组。
        insert_before_marker: 在此标记行之前插入换板 G-code。
    """
    rules: tuple[GcodePatchRule, ...]
    insert_before_marker: str = DEFAULT_INSERT_BEFORE_MARKER


@dataclass(frozen=True)
class BuildOptions:
    """构建打包选项。

    Attributes:
        swap_gcode: 换板 G-code 文件路径或内容字符串。
        output_3mf: 输出 3MF 文件的保存路径。
        cool_bed_temp: 冷却热床目标温度（摄氏度），None 表示不等待冷却。
        wait_after_eject_seconds: 推板后等待秒数。
        show_plate_number: 是否在屏幕上显示当前板件编号。
        swap_after_final: 最终板件完成后是否也执行换板。
        metadata_mode: 元数据模式，"source" 取源文件值，"sum" 累加求和。
        line_ending: 输出 G-code 的换行符风格。
        add_preview_label: 是否为板件添加预览标签注释。
        apply_gcode_patches: 是否应用 G-code 补丁规则。
        swap_gcode_dir: 换板 G-code 文件所在目录，默认自动检测。
        zip_compress_level: 3MF (ZIP) 压缩级别，默认 7。
    """
    swap_gcode: Path | str
    output_3mf: Path
    cool_bed_temp: int | None = 45                     # 热床冷却目标温度，None 跳过冷却
    wait_after_eject_seconds: int = 45                 # 推板完成后等待时间
    show_plate_number: bool = True                     # 是否显示板件编号到屏幕
    swap_after_final: bool = True                      # 最后一块是否也换板
    metadata_mode: MetadataMode = "sum"               # 元数据计算模式
    line_ending: LineEnding = "crlf"                   # 输出换行符
    add_preview_label: bool = True                     # 是否添加预览注释
    apply_gcode_patches: bool = True                   # 是否启用 G-code 补丁
    swap_gcode_dir: Path | None = None                 # 换板 G-code 所在目录
    zip_compress_level: int = DEFAULT_ZIP_COMPRESS_LEVEL  # ZIP 压缩级别


@dataclass
class PlateSource:
    """单板 G-code 来源数据。

    Attributes:
        source_3mf: 来源 3MF 文件。
        member_name: 3MF 内部成员名称，用于正确提取 G-code。
        gcode_text: 提取出的 G-code 文本内容。
        prediction_seconds: 预估打印时间（秒）。
        weight_grams: 预估耗材重量（克）。
        filament_used_m: 预估耗材用量（米）。
        filament_used_g: 预估耗材用量（克），部分切片软件以此字段为主。
    """
    source_3mf: Path
    member_name: str                       # 3MF 内的成员名，用于定位 G-code
    gcode_text: str                        # 完整的 G-code 文本
    prediction_seconds: float | None = None  # 预估打印时间（秒）
    weight_grams: float | None = None        # 预估耗材重量（克）
    filament_used_m: float | None = None     # 耗材用量（米）
    filament_used_g: float | None = None     # 耗材用量（克）


@dataclass(frozen=True)
class ThreeMfSummary:
    """单个 3MF 文件的元数据摘要。

    Attributes:
        source_3mf: 来源 3MF 文件。
        plate_count: 该文件中包含的板件数量。
        prediction_seconds: 预估打印时间（秒）。
        weight_grams: 预估耗材重量（克）。
        filament_used_m: 预估耗材用量（米）。
        filament_used_g: 预估耗材用量（克）。
    """
    source_3mf: Path
    plate_count: int                        # 板件数量
    prediction_seconds: float | None = None
    weight_grams: float | None = None
    filament_used_m: float | None = None
    filament_used_g: float | None = None


@dataclass(frozen=True)
class BuildSummary:
    """总体构建摘要。

    Attributes:
        plate_count: 总板件数。
        total_prediction_seconds: 总预估打印时间（秒）。
        total_weight_grams: 总耗材重量（克）。
        total_filament_used_m: 总耗材用量（米）。
        total_filament_used_g: 总耗材用量（克）。
    """
    plate_count: int
    total_prediction_seconds: float | None  # 总预估时间
    total_weight_grams: float | None        # 总耗材重量
    total_filament_used_m: float | None     # 总耗材长度
    total_filament_used_g: float | None     # 总耗材质量


@dataclass
class BuildResult:
    """单次构建打包的最终结果。

    Attributes:
        output_3mf: 输出 3MF 文件路径。
        plate_count: 包含的板件总数。
        total_prediction_seconds: 总预估打印时间（秒）。
        total_weight_grams: 总耗材重量（克）。
        gcode_md5: 最终 G-code 内容的 MD5 哈希值，用于唯一性校验。
    """
    output_3mf: Path
    plate_count: int
    total_prediction_seconds: float | None
    total_weight_grams: float | None
    gcode_md5: str                           # G-code MD5 哈希值
