import logging
import subprocess
from datetime import datetime, timedelta
from pathlib import Path

from sqlalchemy import select, update
from sqlalchemy.orm import Session

from app.core.config import settings
from app.core.paths import data_path
from app.db.session import get_db
from app.models import Certificate

logger = logging.getLogger(__name__)


def cleanup_expired_pdfs() -> dict:
    """
    清理超过指定天数未访问的PDF文件

    Returns:
        dict: 清理结果统计
    """
    logger.info("[PDF清理] 开始清理过期PDF文件...")

    # 使用配置中的清理天数
    cleanup_days = settings.pdf_cleanup_days

    # 计算截止时间
    cutoff_time = datetime.utcnow() - timedelta(days=cleanup_days)

    # 统计结果
    result = {
        "total_checked": 0,
        "cleaned_files": 0,
        "cleaned_records": 0,
        "cleanup_days": cleanup_days,
        "errors": [],
    }

    try:
        # 获取数据库会话
        db = next(get_db())

        # 查询需要清理的证书
        # 条件：PDF已生成，且最后访问时间早于截止时间，或从未访问过
        stmt = select(Certificate).where(
            Certificate.pdf_status == "generated",
            Certificate.pdf_file_path.isnot(None),
            (
                (Certificate.pdf_last_accessed_at < cutoff_time) |
                (Certificate.pdf_last_accessed_at.is_(None))
            )
        )

        certificates = db.execute(stmt).scalars().all()
        result["total_checked"] = len(certificates)

        for cert in certificates:
            try:
                # 删除PDF文件
                if cert.pdf_file_path:
                    pdf_path = Path(cert.pdf_file_path)
                    if pdf_path.exists():
                        subprocess.run(["rm", "-f", str(pdf_path)], check=False)
                        result["cleaned_files"] += 1
                        logger.info(f"[PDF清理] 已删除文件: {cert.pdf_file_path}")

                # 更新数据库记录
                cert.pdf_status = "cleaned"
                cert.pdf_file_path = None
                cert.pdf_last_accessed_at = None
                result["cleaned_records"] += 1

            except Exception as e:
                error_msg = f"清理证书 {cert.certificate_no} 失败: {str(e)}"
                result["errors"].append(error_msg)
                logger.error(f"[PDF清理] {error_msg}")

        # 提交数据库更改
        db.commit()

        logger.info(f"[PDF清理] 清理完成: 检查 {result['total_checked']} 个, "
                    f"删除 {result['cleaned_files']} 个文件, "
                    f"更新 {result['cleaned_records']} 条记录")

    except Exception as e:
        logger.error(f"[PDF清理] 清理过程发生错误: {str(e)}")
        result["errors"].append(f"清理过程发生错误: {str(e)}")

    return result


def get_pdf_cleanup_stats() -> dict:
    """
    获取PDF清理统计信息

    Returns:
        dict: 统计信息
    """
    try:
        db = next(get_db())

        # 使用配置中的清理天数
        cleanup_days = settings.pdf_cleanup_days

        # 统计总数
        total_stmt = select(Certificate).where(Certificate.pdf_status == "generated")
        total_count = len(db.execute(total_stmt).scalars().all())

        # 统计需要清理的
        cutoff_time = datetime.utcnow() - timedelta(days=cleanup_days)
        cleanup_stmt = select(Certificate).where(
            Certificate.pdf_status == "generated",
            Certificate.pdf_file_path.isnot(None),
            (
                (Certificate.pdf_last_accessed_at < cutoff_time) |
                (Certificate.pdf_last_accessed_at.is_(None))
            )
        )
        cleanup_count = len(db.execute(cleanup_stmt).scalars().all())

        # 统计PDF文件大小
        total_size = 0
        pdf_cache_dir = data_path("pdf-cache")
        if pdf_cache_dir.exists():
            for pdf_file in pdf_cache_dir.rglob("*.pdf"):
                total_size += pdf_file.stat().st_size

        return {
            "total_pdfs": total_count,
            "need_cleanup": cleanup_count,
            "total_size_mb": round(total_size / (1024 * 1024), 2),
            "cleanup_days": cleanup_days,
        }

    except Exception as e:
        logger.error(f"[PDF统计] 获取统计信息失败: {str(e)}")
        return {
            "total_pdfs": 0,
            "need_cleanup": 0,
            "total_size_mb": 0,
            "cleanup_days": settings.pdf_cleanup_days,
            "error": str(e),
        }


def manual_cleanup_certificate(certificate_no: str) -> bool:
    """
    手动清理指定证书的PDF文件

    Args:
        certificate_no: 证书编号

    Returns:
        bool: 是否成功清理
    """
    try:
        db = next(get_db())

        # 查询证书
        stmt = select(Certificate).where(Certificate.certificate_no == certificate_no)
        cert = db.execute(stmt).scalar_one_or_none()

        if not cert:
            logger.warning(f"[手动清理] 证书不存在: {certificate_no}")
            return False

        # 删除PDF文件
        if cert.pdf_file_path:
            pdf_path = Path(cert.pdf_file_path)
            if pdf_path.exists():
                subprocess.run(["rm", "-f", str(pdf_path)], check=False)
                logger.info(f"[手动清理] 已删除文件: {cert.pdf_file_path}")

        # 更新数据库记录
        cert.pdf_status = "cleaned"
        cert.pdf_file_path = None
        cert.pdf_last_accessed_at = None

        db.commit()

        logger.info(f"[手动清理] 清理完成: {certificate_no}")
        return True

    except Exception as e:
        logger.error(f"[手动清理] 清理失败: {certificate_no}, 错误: {str(e)}")
        return False
