#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：deploy_execution.py
模块描述：部署执行记录数据库模型定义

作者：czj
创建日期：2026-08-12
最后修改：2026-08-12
"""

from datetime import datetime
from typing import Optional
from sqlalchemy import String, Integer, Float, Text, DateTime, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.database import Base
from app.utils.id_generator import generate_id


class DeployExecution(Base):
    """
    部署执行记录

    记录每次部署执行的整体信息，包含脚本/服务器快照。

    Attributes:
        id (str): 执行记录唯一标识
        script_id (str): 关联的脚本配置 ID
        server_id (str): 关联的目标服务器 ID
        script_name (str): 快照：脚本名称
        server_name (str): 快照：服务器名称
        server_host (str): 快照：服务器地址
        remote_command (str): 快照：执行的命令
        status (str): 状态 (pending/running/completed/failed/cancelled)
        start_time (datetime): 开始时间
        end_time (datetime): 结束时间
        duration (float): 耗时（秒）
        exit_code (int): 退出码
        error_message (str): 错误信息
        trigger_by (str): 触发人
        created_at (datetime): 创建时间
    """

    __tablename__ = "deploy_executions"

    id: Mapped[str] = mapped_column(
        String(64), primary_key=True, default=lambda: generate_id("deploy_exec"),
        comment="执行记录唯一标识"
    )
    script_id: Mapped[str] = mapped_column(
        String(64), ForeignKey("deploy_scripts.id", ondelete="SET NULL"),
        nullable=False, comment="关联的脚本配置 ID"
    )
    server_id: Mapped[str] = mapped_column(
        String(64), nullable=False, comment="关联的目标服务器 ID"
    )
    script_name: Mapped[str] = mapped_column(
        String(200), default="", comment="快照：脚本名称"
    )
    server_name: Mapped[str] = mapped_column(
        String(100), default="", comment="快照：服务器名称"
    )
    server_host: Mapped[str] = mapped_column(
        String(255), default="", comment="快照：服务器地址"
    )
    remote_command: Mapped[str] = mapped_column(
        String(1000), default="", comment="快照：执行的命令"
    )
    status: Mapped[str] = mapped_column(
        String(20), default="pending",
        comment="状态: pending/running/completed/failed/cancelled"
    )
    start_time: Mapped[Optional[datetime]] = mapped_column(
        DateTime, nullable=True, comment="开始时间"
    )
    end_time: Mapped[Optional[datetime]] = mapped_column(
        DateTime, nullable=True, comment="结束时间"
    )
    duration: Mapped[float] = mapped_column(
        Float, default=0.0, comment="耗时（秒）"
    )
    exit_code: Mapped[Optional[int]] = mapped_column(
        Integer, nullable=True, comment="退出码"
    )
    error_message: Mapped[Optional[str]] = mapped_column(
        Text, nullable=True, comment="错误信息"
    )
    trigger_by: Mapped[str] = mapped_column(
        String(100), default="", comment="触发人"
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime, default=datetime.utcnow, comment="创建时间"
    )

    # 关联脚本配置
    script: Mapped[Optional["DeployScript"]] = relationship(
        "DeployScript", back_populates="executions"
    )

    # 关联执行日志（一对多）
    logs: Mapped[list["DeployLog"]] = relationship(
        "DeployLog",
        back_populates="execution",
        cascade="all, delete-orphan"
    )

    def __repr__(self) -> str:
        return f"<DeployExecution(id={self.id}, status={self.status})>"

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "script_id": self.script_id,
            "server_id": self.server_id,
            "script_name": self.script_name,
            "server_name": self.server_name,
            "server_host": self.server_host,
            "remote_command": self.remote_command,
            "status": self.status,
            "start_time": self.start_time.isoformat() if self.start_time else None,
            "end_time": self.end_time.isoformat() if self.end_time else None,
            "duration": self.duration,
            "exit_code": self.exit_code,
            "error_message": self.error_message,
            "trigger_by": self.trigger_by,
            "created_at": self.created_at.isoformat() if self.created_at else None,
        }