#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Generate DataPointer White Paper PPT with screenshots."""

import os
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from io import BytesIO
from PIL import Image

# Config
SCREENSHOT_DIR = '/Users/nathan/Work/DataPointer/prop-data-guard/screenshots'
OUTPUT_PATH = '/Users/nathan/Work/DataPointer/DataPointer产品介绍白皮书.pptx'
SLIDE_WIDTH = Inches(13.333)
SLIDE_HEIGHT = Inches(7.5)

# Color theme
COLOR_PRIMARY = RGBColor(0x1A, 0x56, 0xDB)      # Deep blue
COLOR_SECONDARY = RGBColor(0x10, 0xB9, 0x81)    # Green
COLOR_DARK = RGBColor(0x1E, 0x29, 0x3B)         # Dark slate
COLOR_TEXT = RGBColor(0x37, 0x41, 0x51)         # Gray text
COLOR_LIGHT = RGBColor(0xF8, 0xFA, 0xFC)        # Light bg
COLOR_ACCENT = RGBColor(0xF5, 0x9E, 0x0B)       # Orange accent


def add_title_slide(prs, title, subtitle):
    slide = prs.slides.add_slide(prs.slide_layouts[6])  # blank
    slide.shapes._spTree.remove(slide.shapes._spTree[0]) if len(slide.shapes._spTree) > 0 else None

    # Background shape
    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, SLIDE_HEIGHT)
    bg.fill.solid()
    bg.fill.fore_color.rgb = COLOR_DARK
    bg.line.fill.background()

    # Accent bar
    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(0.8), Inches(3.0), Inches(0.15), Inches(2.2))
    bar.fill.solid()
    bar.fill.fore_color.rgb = COLOR_PRIMARY
    bar.line.fill.background()

    # Title
    title_box = slide.shapes.add_textbox(Inches(1.2), Inches(2.8), Inches(10), Inches(1.5))
    tf = title_box.text_frame
    tf.word_wrap = True
    p = tf.paragraphs[0]
    p.text = title
    p.font.size = Pt(48)
    p.font.bold = True
    p.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)

    # Subtitle
    sub_box = slide.shapes.add_textbox(Inches(1.2), Inches(4.4), Inches(10), Inches(0.8))
    tf = sub_box.text_frame
    p = tf.paragraphs[0]
    p.text = subtitle
    p.font.size = Pt(22)
    p.font.color.rgb = RGBColor(0xA0, 0xAE, 0xC0)

    # Bottom info
    info_box = slide.shapes.add_textbox(Inches(1.2), Inches(6.5), Inches(10), Inches(0.5))
    tf = info_box.text_frame
    p = tf.paragraphs[0]
    p.text = "Property Insurance Data Classification Platform  |  2026"
    p.font.size = Pt(12)
    p.font.color.rgb = RGBColor(0x71, 0x80, 0x96)

    return slide


def add_section_slide(prs, section_num, section_title):
    slide = prs.slides.add_slide(prs.slide_layouts[6])

    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, SLIDE_HEIGHT)
    bg.fill.solid()
    bg.fill.fore_color.rgb = COLOR_PRIMARY
    bg.line.fill.background()

    num_box = slide.shapes.add_textbox(Inches(0.8), Inches(2.5), Inches(2), Inches(1.5))
    tf = num_box.text_frame
    p = tf.paragraphs[0]
    p.text = f"0{section_num}" if section_num < 10 else str(section_num)
    p.font.size = Pt(72)
    p.font.bold = True
    p.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
    p.font.opacity = 0.3

    title_box = slide.shapes.add_textbox(Inches(0.8), Inches(4.0), Inches(10), Inches(1.0))
    tf = title_box.text_frame
    p = tf.paragraphs[0]
    p.text = section_title
    p.font.size = Pt(40)
    p.font.bold = True
    p.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)

    return slide


def add_content_slide(prs, title, bullets, image_path=None):
    slide = prs.slides.add_slide(prs.slide_layouts[6])

    # Light background
    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, SLIDE_HEIGHT)
    bg.fill.solid()
    bg.fill.fore_color.rgb = COLOR_LIGHT
    bg.line.fill.background()
    # Send to back
    spTree = slide.shapes._spTree
    spTree.insert(2, bg._element)

    # Top bar
    top_bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, Inches(0.12))
    top_bar.fill.solid()
    top_bar.fill.fore_color.rgb = COLOR_PRIMARY
    top_bar.line.fill.background()

    # Title
    title_box = slide.shapes.add_textbox(Inches(0.6), Inches(0.35), Inches(12), Inches(0.6))
    tf = title_box.text_frame
    p = tf.paragraphs[0]
    p.text = title
    p.font.size = Pt(28)
    p.font.bold = True
    p.font.color.rgb = COLOR_DARK

    # Content
    if image_path and os.path.exists(image_path):
        # Image on right, text on left
        content_box = slide.shapes.add_textbox(Inches(0.6), Inches(1.2), Inches(4.5), Inches(5.5))
        tf = content_box.text_frame
        tf.word_wrap = True
        for i, bullet in enumerate(bullets):
            if i == 0:
                p = tf.paragraphs[0]
            else:
                p = tf.add_paragraph()
            p.text = f"• {bullet}"
            p.font.size = Pt(16)
            p.font.color.rgb = COLOR_TEXT
            p.space_after = Pt(12)

        # Add image
        img = Image.open(image_path)
        orig_w, orig_h = img.size
        max_w = Inches(7.0)
        max_h = Inches(5.5)
        ratio = min(max_w / orig_w, max_h / orig_h)
        img_w = orig_w * ratio
        img_h = orig_h * ratio
        left = SLIDE_WIDTH - img_w - Inches(0.6)
        top = Inches(1.0) + (max_h - img_h) / 2
        slide.shapes.add_picture(image_path, left, top, width=img_w, height=img_h)
    else:
        content_box = slide.shapes.add_textbox(Inches(0.6), Inches(1.2), Inches(12), Inches(5.5))
        tf = content_box.text_frame
        tf.word_wrap = True
        for i, bullet in enumerate(bullets):
            if i == 0:
                p = tf.paragraphs[0]
            else:
                p = tf.add_paragraph()
            p.text = f"• {bullet}"
            p.font.size = Pt(18)
            p.font.color.rgb = COLOR_TEXT
            p.space_after = Pt(14)

    return slide


def add_image_slide(prs, title, image_path, caption=""):
    slide = prs.slides.add_slide(prs.slide_layouts[6])

    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, SLIDE_HEIGHT)
    bg.fill.solid()
    bg.fill.fore_color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
    bg.line.fill.background()
    spTree = slide.shapes._spTree
    spTree.insert(2, bg._element)

    top_bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, Inches(0.12))
    top_bar.fill.solid()
    top_bar.fill.fore_color.rgb = COLOR_PRIMARY
    top_bar.line.fill.background()

    title_box = slide.shapes.add_textbox(Inches(0.6), Inches(0.35), Inches(12), Inches(0.5))
    tf = title_box.text_frame
    p = tf.paragraphs[0]
    p.text = title
    p.font.size = Pt(26)
    p.font.bold = True
    p.font.color.rgb = COLOR_DARK

    if os.path.exists(image_path):
        img = Image.open(image_path)
        orig_w, orig_h = img.size
        max_w = Inches(11.5)
        max_h = Inches(5.8)
        ratio = min(max_w / orig_w, max_h / orig_h)
        img_w = orig_w * ratio
        img_h = orig_h * ratio
        left = (SLIDE_WIDTH - img_w) / 2
        top = Inches(1.0)
        slide.shapes.add_picture(image_path, left, top, width=img_w, height=img_h)

    if caption:
        cap_box = slide.shapes.add_textbox(Inches(0.6), Inches(6.9), Inches(12), Inches(0.4))
        tf = cap_box.text_frame
        p = tf.paragraphs[0]
        p.text = caption
        p.font.size = Pt(12)
        p.font.color.rgb = RGBColor(0x71, 0x80, 0x96)
        p.alignment = PP_ALIGN.CENTER

    return slide


def add_summary_slide(prs):
    slide = prs.slides.add_slide(prs.slide_layouts[6])

    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, SLIDE_HEIGHT)
    bg.fill.solid()
    bg.fill.fore_color.rgb = COLOR_DARK
    bg.line.fill.background()

    title_box = slide.shapes.add_textbox(Inches(0.8), Inches(1.5), Inches(11.5), Inches(1.0))
    tf = title_box.text_frame
    p = tf.paragraphs[0]
    p.text = "DataPointer 产品优势"
    p.font.size = Pt(36)
    p.font.bold = True
    p.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)

    items = [
        ("全生命周期数据安全", "从数据采集、分类分级、风险评估到持续监控，覆盖数据安全全生命周期"),
        ("智能自动化引擎", "基于规则+AI的智能分类引擎，自动识别敏感数据，效率提升80%"),
        ("精细化权限管控", "RBAC 角色权限模型，支持数据隔离，满足多租户场景"),
        ("保险行业深度适配", "内置保险行业数据分类分级标准，覆盖客户、保单、理赔等核心领域"),
        ("可视化数据资产", "仪表盘+报表多维展示，数据资产状况一目了然"),
    ]

    y = Inches(2.8)
    for title, desc in items:
        box = slide.shapes.add_textbox(Inches(0.8), y, Inches(11.5), Inches(0.8))
        tf = box.text_frame
        tf.word_wrap = True
        p = tf.paragraphs[0]
        p.text = f"▎ {title}"
        p.font.size = Pt(18)
        p.font.bold = True
        p.font.color.rgb = COLOR_SECONDARY
        p = tf.add_paragraph()
        p.text = f"    {desc}"
        p.font.size = Pt(14)
        p.font.color.rgb = RGBColor(0xA0, 0xAE, 0xC0)
        y += Inches(0.85)

    return slide


def add_end_slide(prs):
    slide = prs.slides.add_slide(prs.slide_layouts[6])

    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_WIDTH, SLIDE_HEIGHT)
    bg.fill.solid()
    bg.fill.fore_color.rgb = COLOR_PRIMARY
    bg.line.fill.background()

    title_box = slide.shapes.add_textbox(Inches(0), Inches(2.8), SLIDE_WIDTH, Inches(1.0))
    tf = title_box.text_frame
    p = tf.paragraphs[0]
    p.text = "谢谢观看"
    p.font.size = Pt(52)
    p.font.bold = True
    p.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
    p.alignment = PP_ALIGN.CENTER

    sub_box = slide.shapes.add_textbox(Inches(0), Inches(4.0), SLIDE_WIDTH, Inches(0.6))
    tf = sub_box.text_frame
    p = tf.paragraphs[0]
    p.text = "DataPointer - 让数据安全触手可及"
    p.font.size = Pt(20)
    p.font.color.rgb = RGBColor(0xA0, 0xAE, 0xC0)
    p.alignment = PP_ALIGN.CENTER

    return slide


def main():
    prs = Presentation()
    prs.slide_width = SLIDE_WIDTH
    prs.slide_height = SLIDE_HEIGHT

    # 1. Cover
    add_title_slide(prs, "DataPointer", "数据安全分级及风险管理平台产品介绍白皮书")

    # 2. TOC
    add_content_slide(prs, "目录", [
        "产品概述与定位",
        "系统架构与技术栈",
        "核心功能模块详解",
        "产品优势与价值",
        "应用场景与最佳实践"
    ])

    # 3. Section: Overview
    add_section_slide(prs, 1, "产品概述")

    add_content_slide(prs, "DataPointer 产品定位", [
        "DataPointer 是面向保险行业的数据安全分级及风险管理平台",
        "基于国家及行业数据分类分级标准，帮助企业实现数据资产的自动化识别与分级",
        "支持从数据源接入、元数据采集、智能分类、人工复核到报表输出的完整工作流",
        "内置保险行业专属分类标准，覆盖客户、保单、理赔、财务、渠道、监管等核心领域",
        "提供多维度数据资产视图，助力企业满足数据安全合规要求"
    ])

    # 4. Section: Architecture
    add_section_slide(prs, 2, "系统架构")

    add_content_slide(prs, "技术架构", [
        "前端：Vue 3.4 + Vite + TypeScript + Element Plus 2.7 + ECharts 5.4",
        "后端：FastAPI 0.111 + SQLAlchemy 2.0 + PostgreSQL 16 + Redis 7 + Celery 5.4",
        "部署：容器化部署，支持 Docker Compose / Kubernetes",
        "安全：JWT 认证 + RBAC 权限控制 + 数据隔离，满足等保要求",
        "扩展：模块化设计，支持自定义分类标准与规则引擎扩展"
    ])

    # 5. Section: Features
    add_section_slide(prs, 3, "核心功能")

    add_image_slide(prs, "安全登录与权限管控", os.path.join(SCREENSHOT_DIR, "01_login.png"),
                    "支持用户名密码登录，JWT Token 认证，会话安全")

    add_image_slide(prs, "仪表盘总览", os.path.join(SCREENSHOT_DIR, "02_dashboard.png"),
                    "实时展示数据源、表、字段、分级结果等核心指标，支持敏感数据分布可视化")

    add_content_slide(prs, "数据源管理", [
        "支持多种数据库类型接入：MySQL、PostgreSQL、Oracle、SQL Server 等",
        "自动扫描数据库元数据，采集表结构与字段信息",
        "支持数据源连接测试与状态监控",
        "批量导入导出数据源配置，提升运维效率"
    ], os.path.join(SCREENSHOT_DIR, "03_datasource.png"))

    add_content_slide(prs, "数据资产管理", [
        "自动生成数据资产目录，展示数据库、表、字段的层级关系",
        "支持字段级元数据查看，包括数据类型、注释、采样数据等",
        "资产变更追踪，记录元数据的增删改历史",
        "与分类分级结果联动，直观展示各资产的安全等级"
    ], os.path.join(SCREENSHOT_DIR, "04_metadata.png"))

    add_content_slide(prs, "分类分级标准", [
        "内置保险行业五级分类标准：公开级(L1)、内部级(L2)、敏感级(L3)、重要级(L4)、核心级(L5)",
        "支持自定义分类标准与分级规则，灵活适配不同业务场景",
        "规则引擎支持正则匹配、关键字匹配、语义识别等多种检测方式",
        "标准模板管理，支持一键导入导出行业标准模板"
    ], os.path.join(SCREENSHOT_DIR, "05_category.png"))

    add_content_slide(prs, "项目管理", [
        "支持创建多个分类分级项目，独立管理与进度跟踪",
        "项目维度统计：自动识别、人工标注、已复核数量",
        "支持批量触发自动分类任务，提升处理效率",
        "项目经理可查看负责项目的全部进度与成果"
    ], os.path.join(SCREENSHOT_DIR, "06_project.png"))

    add_content_slide(prs, "任务管理", [
        "自动拆解项目为标注/复核任务，分配给标注员与审核员",
        "任务状态追踪：待处理、处理中、已完成、已驳回",
        "支持任务领取与批量处理，提升团队协作效率",
        "数据隔离：普通用户仅能查看和处理分配给自己的任务"
    ], os.path.join(SCREENSHOT_DIR, "07_task.png"))

    add_content_slide(prs, "分类分级结果", [
        "展示所有字段的分类分级结果，支持多维筛选与搜索",
        "结果包含：字段名称、所属表/库、分类标准、安全等级、识别方式",
        "支持结果的批量导出，便于合规审计与报告生成",
        "人工复核机制，确保分类分级的准确性与权威性"
    ], os.path.join(SCREENSHOT_DIR, "08_classification.png"))

    add_content_slide(prs, "报表统计", [
        "多维统计报表：按等级分布、类别分布、数据源分布等维度展示",
        "支持 Word 报告一键生成，包含完整的数据资产与分级详情",
        "可视化图表直观展示敏感数据分布与趋势",
        "满足监管报送与内部审计的数据安全报告需求"
    ], os.path.join(SCREENSHOT_DIR, "09_report.png"))

    add_content_slide(prs, "系统管理", [
        "用户管理：支持用户增删改查、角色分配、部门归属",
        "角色权限：基于 RBAC 模型，支持 admin、project_manager、labeler、reviewer、guest 等角色",
        "数据隔离：严格的数据权限控制，确保跨部门数据安全",
        "操作日志：完整记录用户操作行为，支持安全审计"
    ], os.path.join(SCREENSHOT_DIR, "10_system.png"))

    # 6. Section: Advantages
    add_section_slide(prs, 4, "产品优势")
    add_summary_slide(prs)

    # 7. Section: Scenarios
    add_section_slide(prs, 5, "应用场景")

    add_content_slide(prs, "典型应用场景", [
        "数据安全合规：帮助企业满足《数据安全法》《个人信息保护法》等法规要求",
        "等保测评：提供完整的数据分类分级证据链，支撑等级保护测评",
        "数据资产盘点：全面梳理企业数据资产，建立统一的数据资产目录",
        "敏感数据发现：自动识别客户身份证号、银行卡号、保单信息等敏感字段",
        "数据分级保护：根据分级结果制定差异化的数据安全保护策略"
    ])

    # 8. End
    add_end_slide(prs)

    prs.save(OUTPUT_PATH)
    print(f"PPT saved to: {OUTPUT_PATH}")


if __name__ == "__main__":
    main()
