#!/usr/bin/env python3
"""Docmee AiPPT 统一入口。

支持以下输入方式：
  - 主题/标题生成
  - 上传文件生成
  - 网页 URL 生成
  - 纯文本生成
  - Markdown 大纲生成

额外支持：
  - 上传自定义模板后生成时指定模板
  - 对已有 pptId 直接更换模板
  - 使用已有 templateId 生成
  - 使用 outline 内容覆盖自动生成的大纲
"""

from __future__ import annotations

import argparse
import os
import re
import sys
from pathlib import Path

from provider_docmee import (
    download_file,
    generate_content,
    generate_outline,
    generate_pptx,
    parse_file_data,
    random_template_id,
    update_ppt_template,
    upload_template,
    wait_for_download_url,
)


MARKDOWN_EXTENSIONS = {".md", ".markdown"}
DEFAULT_OUTPUT_DIR = "/home/node/.openclaw/workspace/media/inbound/ppt"


def _is_markdown_content(text: str) -> bool:
    stripped = text.strip()
    if stripped.startswith("#"):
        return True

    indicators = 0
    for line in stripped.splitlines()[:30]:
        value = line.strip()
        if value.startswith(("## ", "### ", "- ", "* ", "```")):
            indicators += 1
    return indicators >= 2


def detect_mode(
    *,
    file_path: str | None,
    url: str | None,
    content: str | None,
    content_file: str | None,
) -> str:
    if file_path:
        ext = Path(file_path).suffix.lower()
        if ext in MARKDOWN_EXTENSIONS:
            return "markdown"
        return "file"
    if url:
        return "website"
    if content_file:
        ext = Path(content_file).suffix.lower()
        return "markdown" if ext in MARKDOWN_EXTENSIONS else "text"
    if content:
        return "markdown" if _is_markdown_content(content) else "text"
    return "subject"


def _read_text_file(path: str, label: str) -> str:
    file = Path(path)
    if not file.exists():
        raise RuntimeError(f"{label}不存在: {path}")
    return file.read_text(encoding="utf-8")


def _resolve_outline_override(outline_content: str, outline_file: str | None) -> str:
    if outline_file:
        return _read_text_file(outline_file, "大纲文件")
    return outline_content


def _resolve_content(content: str, content_file: str | None) -> str:
    if content_file:
        return _read_text_file(content_file, "内容文件")
    return content


def _resolve_markdown_input(file_path: str | None, content: str) -> str:
    if file_path:
        return _read_text_file(file_path, "Markdown 文件")
    return content


def _build_prompt(style: str) -> str | None:
    style = style.strip()
    if not style:
        return None
    return f"请按照“{style}”的视觉风格与表达方式生成 PPT，保证排版协调、内容专业。"


def _safe_filename(name: str) -> str:
    cleaned = re.sub(r'[\\/:*?"<>|]+', "_", name).strip()
    return cleaned or "aippt-new"


def _resolve_template(template_id: str | None, template_file: str | None) -> str:
    resolved = template_id

    if template_file:
        if not Path(template_file).exists():
            raise RuntimeError(f"模板文件不存在: {template_file}")
        print("\n\n========== Step 1: 上传自定义模板 ==========")
        resolved = upload_template(template_file, template_id)
        print(f"template_id = {resolved}")
        return resolved

    if resolved:
        return resolved

    print("\n\n========== Step 1: 随机选择模板 ==========")
    resolved = random_template_id()
    print(f"template_id = {resolved}")
    return resolved


def _resolve_replace_template(template_id: str | None, template_file: str | None) -> str | None:
    resolved = template_id

    if template_file:
        if not Path(template_file).exists():
            raise RuntimeError(f"替换模板文件不存在: {template_file}")
        print("\n\n========== Step X: 上传替换模板 ==========")
        resolved = upload_template(template_file, template_id)
        print(f"replace_template_id = {resolved}")
        return resolved

    return resolved


def _resolve_existing_ppt_template(
    template_id: str | None,
    template_file: str | None,
    replace_template_id: str | None,
    replace_template_file: str | None,
) -> str:
    resolved = _resolve_replace_template(replace_template_id, replace_template_file)
    if resolved:
        return resolved

    if template_file:
        if not Path(template_file).exists():
            raise RuntimeError(f"模板文件不存在: {template_file}")
        print("\n\n========== Step 1: 上传自定义模板 ==========")
        resolved = upload_template(template_file, template_id)
        print(f"template_id = {resolved}")
        return resolved

    if template_id:
        return template_id

    raise RuntimeError(
        "指定 --ppt-id 时，必须提供 --template-id / --template-file "
        "或 --replace-template-id / --replace-template-file"
    )


def _extract_ppt_id(ppt_info: dict) -> str:
    for key in ("id", "pptId"):
        value = ppt_info.get(key)
        if value:
            return str(value)
    raise RuntimeError("生成 PPT 失败: 返回结果中缺少 pptId")


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Docmee AiPPT 统一入口",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument("--title", required=False, help="PPT 标题")
    parser.add_argument("--ppt-id", default=None, help="已有 PPT 的 ID；指定后直接更换模板")
    parser.add_argument("--file", dest="file_path", default=None, help="上传文件路径")
    parser.add_argument("--url", default=None, help="网页 URL")
    parser.add_argument("--content", default="", help="内容文本或 Markdown")
    parser.add_argument("--content-file", default=None, help="从文件读取内容")
    parser.add_argument("--template-id", default=None, help="指定模板 ID")
    parser.add_argument("--template-file", default=None, help="上传自定义模板文件")
    parser.add_argument("--replace-template-id", default=None, help="生成后更换为指定模板 ID")
    parser.add_argument("--replace-template-file", default=None, help="生成后更换为上传的模板文件")
    parser.add_argument(
        "--replace-template-sync",
        action="store_true",
        help="更换模板时使用同步模式（默认异步）",
    )
    parser.add_argument("--style", default="", help="风格提示，例如“深蓝 科技”")
    parser.add_argument("--outline-content", default="", help="覆盖自动生成的大纲内容")
    parser.add_argument("--outline-file", default=None, help="从文件读取大纲内容")
    parser.add_argument(
        "--output",
        default=None,
        help="保存路径（默认：/home/node/.openclaw/workspace/media/inbound/ppt/<标题>.pptx）",
    )
    args = parser.parse_args()

    try:
        if not args.title and not args.ppt_id:
            raise RuntimeError("必须提供 --title，或使用 --ppt-id 对已有 PPT 更换模板")
        if args.file_path and not Path(args.file_path).exists():
            raise RuntimeError(f"输入文件不存在: {args.file_path}")

        if args.ppt_id:
            target_template_id = _resolve_existing_ppt_template(
                args.template_id,
                args.template_file,
                args.replace_template_id,
                args.replace_template_file,
            )
            print(f"\n[模式识别] mode=replace-existing-ppt")
            print("\n\n========== Step 2: 更换 PPT 模板 ==========")
            replace_result = update_ppt_template(
                args.ppt_id,
                target_template_id,
                # 直接操作已有 PPT 时默认走同步，更稳妥。
                sync=args.replace_template_sync or True,
            )
            print(f"ppt_id = {args.ppt_id}")
            print(f"replace_template_id = {target_template_id}")
            if replace_result.get("pptId"):
                print(f"replace_ppt_id = {replace_result.get('pptId')}")

            print("\n\n========== Step 3: 等待下载链接 ==========")
            file_url = wait_for_download_url(args.ppt_id)
            output_basename = _safe_filename(args.title) if args.title else args.ppt_id
            output_path = args.output or os.path.join(
                DEFAULT_OUTPUT_DIR,
                f"{output_basename}.pptx",
            )
            Path(output_path).parent.mkdir(parents=True, exist_ok=True)
            print("\n\n========== 正在下载 PPT ==========")
            download_file(file_url, output_path)
            print(f"PPT 下载完成，保存路径: {output_path}")
            print(f"PPT 下载链接: {file_url}")
            return 0

        input_content = _resolve_content(args.content, args.content_file)
        outline_override = _resolve_outline_override(args.outline_content, args.outline_file)
        mode = detect_mode(
            file_path=args.file_path,
            url=args.url,
            content=input_content,
            content_file=args.content_file,
        )
        prompt = _build_prompt(args.style)

        print(f"\n[模式识别] mode={mode}")
        template_id = _resolve_template(args.template_id, args.template_file)
        replace_template_id = _resolve_replace_template(
            args.replace_template_id,
            args.replace_template_file,
        )

        if mode == "markdown":
            print("\n\n========== Step 2: 准备 Markdown 大纲 ==========")
            markdown = outline_override or _resolve_markdown_input(args.file_path, input_content)
            if not markdown.strip():
                raise RuntimeError("Markdown 内容为空")
            print(f"markdown_length = {len(markdown)}")

            print("\n\n========== Step 3: 生成 PPT ==========")
            ppt_info = generate_pptx(template_id, markdown)
        else:
            step = 2
            data_url = None

            if mode == "file":
                print(f"\n\n========== Step {step}: 解析文件 ==========")
                data_url = parse_file_data(file_path=args.file_path)
                print(f"data_url = {data_url}")
                step += 1
            elif mode == "website":
                print(f"\n\n========== Step {step}: 解析网页 URL ==========")
                data_url = parse_file_data(website=args.url)
                print(f"data_url = {data_url}")
                step += 1
            elif mode == "text":
                if not input_content.strip():
                    raise RuntimeError("文本内容为空")
                print(f"\n\n========== Step {step}: 解析文本内容 ==========")
                data_url = parse_file_data(content=input_content)
                print(f"data_url = {data_url}")
                step += 1

            if outline_override:
                print(f"\n\n========== Step {step}: 使用自定义大纲 ==========")
                outline = outline_override
                print(f"outline_length = {len(outline)}")
                step += 1
            else:
                print(f"\n\n========== Step {step}: 生成大纲 ==========")
                outline = generate_outline(args.title, data_url, prompt)
                print(f"\noutline_length = {len(outline)}")
                step += 1

            print(f"\n\n========== Step {step}: 生成大纲内容 ==========")
            markdown = generate_content(outline, data_url, prompt)
            print(f"\nmarkdown_length = {len(markdown)}")
            step += 1

            print(f"\n\n========== Step {step}: 生成 PPT ==========")
            ppt_info = generate_pptx(template_id, markdown)

        ppt_id = _extract_ppt_id(ppt_info)
        print(f"ppt_id = {ppt_id}")
        if ppt_info.get("subject"):
            print(f"ppt_subject = {ppt_info.get('subject')}")

        file_url = ppt_info.get("fileUrl")
        if replace_template_id:
            print("\n\n========== Step 4: 更换 PPT 模板 ==========")
            replace_result = update_ppt_template(
                ppt_id,
                replace_template_id,
                sync=args.replace_template_sync,
            )
            print(f"replace_template_id = {replace_template_id}")
            if replace_result.get("pptId"):
                print(f"replace_ppt_id = {replace_result.get('pptId')}")
            # 更换模板后必须重新等待最新下载链接，避免拿到变更前文件
            file_url = None

        if not file_url:
            print("\n\n========== Step 5: 等待下载链接 ==========")
            file_url = wait_for_download_url(ppt_id)

        output_path = args.output or os.path.join(
            DEFAULT_OUTPUT_DIR,
            f"{_safe_filename(args.title)}.pptx",
        )
        Path(output_path).parent.mkdir(parents=True, exist_ok=True)

        print("\n\n========== 正在下载 PPT ==========")
        download_file(str(file_url), output_path)
        print(f"PPT 下载完成，保存路径: {output_path}")
        print(f"PPT 下载链接: {file_url}")
        return 0
    except RuntimeError as exc:
        print(f"错误：{exc}", file=sys.stderr)
        return 1


if __name__ == "__main__":
    raise SystemExit(main())
