#!/usr/bin/env python3
"""
Markdown -> WeChat Official Account HTML converter
Style: 抟微科技 Tiny Wings brand style
Replaces manual xiumi.us formatting

Usage:
    python md_to_wechat.py input.md -o output.html
    python md_to_wechat.py input.md -o output.html --theme tech
    python md_to_wechat.py input.md --clipboard
"""

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

# ============================================================
# Brand Style Configuration
# ============================================================

BRAND = {
    "company": "抟微科技",
    "article_prefix": "这是抟微科技陪伴你的第",
    "article_suffix": "篇文章",
    "author_prefix": "作者 ▌",
    "end_marker": "·END·",
}

# All themes analyzed from 5 reference articles (2026-08-10, 第108-112篇)
# Reference URLs:
#   - 第112篇: 一纸客诉查不出源头：MOM改造笔记
#   - 第110篇: 困在"按图施工"里的管道预制
#   - 第109篇: MES实施：这五大关键点
#   - 第108篇: SFC逻辑深度全解④
THEMES = {
    "tech": {
        "name": "技术干货",
        "primary": "#0455A2",       # Deep blue (75次, 第109篇主色)
        "secondary": "#375EB5",     # Deep blue variant (67次, 第110篇主色)
        "accent": "#4D9AF3",        # Bright blue (48次, 第108篇主色)
        "gold_accent": "#F9A912",   # Gold/orange (15次, 强调色)
        "gold_light": "#F4D997",    # Light gold (13次, 第110篇)
        "section_bg": "#E8F0FF",    # Light blue section background
        "number_color": "#0455A2",
        "border_color": "#0455A2",
        "text_color": "#3E3E3E",    # Body text (62次)
        "heading_color": "#0455A2",
        "quote_bg": "#EFF8FF",      # Very light blue (6次)
        "quote_border": "#4D9AF3",
        "cta_bg": "#E8F0FF",
        "end_color": "#999999",
        "link_color": "#2B77D0",    # Medium blue (25次, 跨文章通用)
    },
    "industry": {
        "name": "行业洞察",
        "primary": "#375EB5",       # Deep blue (67次, 第110篇)
        "secondary": "#4D9AF3",     # Bright blue (48次)
        "accent": "#2B77D0",
        "gold_accent": "#F4D997",   # Light gold (13次, 第110篇)
        "gold_light": "#F4D997",
        "section_bg": "#E8F0FF",
        "number_color": "#375EB5",
        "border_color": "#375EB5",
        "text_color": "#3E3E3E",
        "heading_color": "#375EB5",
        "quote_bg": "#EFF8FF",
        "quote_border": "#375EB5",
        "cta_bg": "#E8F0FF",
        "end_color": "#999999",
        "link_color": "#2B77D0",
    },
    "exhibition": {
        "name": "展会活动",
        "primary": "#5F9CEF",       # Light blue (18次, 第112篇)
        "secondary": "#386AC3",     # Medium blue (8次)
        "accent": "#90CFFF",        # Pale blue (12次)
        "gold_accent": "#F9A912",
        "gold_light": "#F4D997",
        "section_bg": "#EAF5FF",
        "number_color": "#5F9CEF",
        "border_color": "#386AC3",
        "text_color": "#3E3E3E",
        "heading_color": "#386AC3",
        "quote_bg": "#EFF8FF",
        "quote_border": "#5F9CEF",
        "cta_bg": "#EAF5FF",
        "end_color": "#999999",
        "link_color": "#386AC3",
    },
    "culture": {
        # 真实文化类文章用的暖色调！与蓝色系形成鲜明对比
        # 适用于妇女节致敬、年会回顾、节日祝福等
        "name": "企业文化",
        "primary": "#84060F",       # Crimson red (analyzed from culture article)
        "secondary": "#C12C2F",     # Deeper red
        "accent": "#FFECD3",        # Warm cream (analyzed)
        "gold_accent": "#F9A912",
        "gold_light": "#FFECD3",
        "section_bg": "#FFF8F0",    # Very light warm cream
        "number_color": "#84060F",
        "border_color": "#C12C2F",
        "text_color": "#3E3E3E",
        "heading_color": "#84060F",
        "quote_bg": "#FFF8F0",
        "quote_border": "#84060F",
        "cta_bg": "#FFF8F0",
        "end_color": "#999999",
        "link_color": "#84060F",
    },
    "marketing": {
        "name": "营销推广",
        "primary": "#0455A2",
        "secondary": "#F9A912",     # Gold accent for marketing
        "accent": "#4D9AF3",
        "gold_accent": "#F9A912",
        "gold_light": "#F4D997",
        "section_bg": "#E8F0FF",
        "number_color": "#0455A2",
        "border_color": "#0455A2",
        "text_color": "#3E3E3E",
        "heading_color": "#0455A2",
        "quote_bg": "#EFF8FF",
        "quote_border": "#0455A2",
        "cta_bg": "#E8F0FF",
        "end_color": "#999999",
        "link_color": "#2B77D0",
    },
    "default": {
        "name": "默认",
        "primary": "#0455A2",       # Deep blue (brand primary)
        "secondary": "#375EB5",
        "accent": "#4D9AF3",
        "gold_accent": "#F9A912",
        "gold_light": "#F4D997",
        "section_bg": "#E8F0FF",
        "number_color": "#0455A2",
        "border_color": "#0455A2",
        "text_color": "#3E3E3E",
        "heading_color": "#0455A2",
        "quote_bg": "#EFF8FF",
        "quote_border": "#4D9AF3",
        "cta_bg": "#E8F0FF",
        "end_color": "#999999",
        "link_color": "#2B77D0",
    },
}


# ============================================================
# Markdown Parser (simplified, no external deps)
# ============================================================

class MarkdownParser:
    """Lightweight Markdown parser that outputs styled HTML for WeChat."""

    def __init__(self, theme="tech"):
        self.theme = THEMES.get(theme, THEMES["tech"])
        self.lines = []
        self.html_parts = []
        self.i = 0
        self.in_list = False
        self.list_type = None  # 'ordered' or 'unordered'

    def parse(self, markdown_text):
        """Parse markdown text and return styled HTML."""
        # Normalize line endings
        text = markdown_text.replace("\r\n", "\n").replace("\r", "\n")
        self.lines = text.split("\n")
        self.i = 0
        self.html_parts = []

        while self.i < len(self.lines):
            line = self.lines[self.i].rstrip()
            self._process_line(line)
            self.i += 1

        # Close any open list
        if self.in_list:
            self.html_parts.append(f"</{self.list_type}>")
            self.in_list = False

        return "\n".join(self.html_parts)

    def _process_line(self, line):
        # Skip empty lines but close lists
        if not line.strip():
            if self.in_list:
                self.html_parts.append(f"</{self.list_type}>")
                self.in_list = False
            return

        # H1 - Main title
        if line.startswith("# ") and not line.startswith("## "):
            title = line[2:].strip()
            self.html_parts.append(self._style_h1(title))
            return

        # H2 - Section header
        if line.startswith("## "):
            title = line[3:].strip()
            if self.in_list:
                self.html_parts.append(f"</{self.list_type}>")
                self.in_list = False
            self.html_parts.append(self._style_h2(title))
            return

        # H3 - Sub-section header
        if line.startswith("### "):
            title = line[4:].strip()
            if self.in_list:
                self.html_parts.append(f"</{self.list_type}>")
                self.in_list = False
            self.html_parts.append(self._style_h3(title))
            return

        # H4
        if line.startswith("#### "):
            title = line[5:].strip()
            self.html_parts.append(self._style_h4(title))
            return

        # Horizontal rule
        if re.match(r'^---+$', line.strip()) or re.match(r'^\*\*\*+$', line.strip()):
            self.html_parts.append(self._style_hr())
            return

        # Blockquote
        if line.startswith("> "):
            content = line[2:].strip()
            # Collect multi-line blockquote
            while self.i + 1 < len(self.lines) and self.lines[self.i + 1].startswith("> "):
                self.i += 1
                content += "<br/>" + self.lines[self.i][2:].strip()
            self.html_parts.append(self._style_blockquote(content))
            return

        # Ordered list item
        if re.match(r'^\d+[\.\)]\s', line):
            content = re.sub(r'^\d+[\.\)]\s*', '', line)
            if not self.in_list or self.list_type != "ol":
                if self.in_list:
                    self.html_parts.append(f"</{self.list_type}>")
                self.html_parts.append("<ol>")
                self.in_list = True
                self.list_type = "ol"
            self.html_parts.append(f"<li>{self._inline_format(content)}</li>")
            return

        # Unordered list item
        if re.match(r'^[-*+]\s', line):
            content = re.sub(r'^[-*+]\s*', '', line)
            if not self.in_list or self.list_type != "ul":
                if self.in_list:
                    self.html_parts.append(f"</{self.list_type}>")
                self.html_parts.append("<ul>")
                self.in_list = True
                self.list_type = "ul"
            self.html_parts.append(f"<li>{self._inline_format(content)}</li>")
            return

        # Image
        img_match = re.match(r'^!\[(.*?)\]\((.*?)\)', line)
        if img_match:
            if self.in_list:
                self.html_parts.append(f"</{self.list_type}>")
                self.in_list = False
            alt = img_match.group(1)
            src = img_match.group(2)
            self.html_parts.append(self._style_image(src, alt))
            return

        # Special markers
        stripped = line.strip()

        # Article number marker
        if stripped.startswith(BRAND["article_prefix"]):
            self.html_parts.append(self._style_article_header(stripped))
            return

        # Author line
        if stripped.startswith(BRAND["author_prefix"]):
            self.html_parts.append(self._style_author(stripped))
            return

        # END marker
        if stripped == BRAND["end_marker"]:
            self.html_parts.append(self._style_end_marker())
            return

        # CTA detection
        if "如果您所在的企业" in stripped and "抟微科技" in stripped:
            # Collect multi-line CTA
            cta_text = stripped
            while self.i + 1 < len(self.lines) and self.lines[self.i + 1].strip():
                next_line = self.lines[self.i + 1].strip()
                if next_line.startswith("#") or next_line.startswith("-") or next_line.startswith(">"):
                    break
                self.i += 1
                cta_text += " " + next_line
            self.html_parts.append(self._style_cta(cta_text))
            return

        # Contact info
        if any(kw in stripped for kw in ["www.tiny-wings", "TinyWings@", "地址:", "电话:", "网址:", "邮箱:"]):
            self.html_parts.append(self._style_contact(stripped))
            return

        # Section number (01, 02, etc.)
        if re.match(r'^\d{2}$', stripped):
            self.html_parts.append(self._style_section_number(stripped))
            return

        # PART header
        if re.match(r'^(PART|Part)\.?\s*\d+', stripped, re.IGNORECASE):
            self.html_parts.append(self._style_part_header(stripped))
            return

        # Regular paragraph
        if self.in_list:
            self.html_parts.append(f"</{self.list_type}>")
            self.in_list = False
        self.html_parts.append(self._style_paragraph(line.strip()))

    # ============================================================
    # Inline Formatting
    # ============================================================

    def _inline_format(self, text):
        """Process inline markdown: bold, italic, code, links."""
        # Images inline
        text = re.sub(
            r'!\[(.*?)\]\((.*?)\)',
            lambda m: f'<img src="{m.group(2)}" alt="{m.group(1)}" '
                      f'style="max-width:100%;border-radius:8px;margin:8px 0;" />',
            text
        )

        # Bold with **
        text = re.sub(
            r'\*\*(.+?)\*\*',
            lambda m: f'<strong style="color:{self.theme["heading_color"]};font-weight:600;">{m.group(1)}</strong>',
            text
        )

        # Italic with *
        text = re.sub(
            r'\*(.+?)\*',
            lambda m: f'<em style="font-style:italic;">{m.group(1)}</em>',
            text
        )

        # Inline code
        text = re.sub(
            r'`(.+?)`',
            lambda m: f'<code style="background:{self.theme["accent"]};'
                      f'padding:2px 6px;border-radius:3px;'
                      f'font-size:14px;font-family:monospace;">{m.group(1)}</code>',
            text
        )

        # Links
        text = re.sub(
            r'\[(.+?)\]\((.+?)\)',
            lambda m: f'<a href="{m.group(2)}" style="color:{self.theme["link_color"]};'
                      f'text-decoration:none;border-bottom:1px solid {self.theme["link_color"]};">'
                      f'{m.group(1)}</a>',
            text
        )

        return text

    # ============================================================
    # Style Templates (all inline CSS for WeChat compatibility)
    # ============================================================

    def _style_h1(self, title):
        """Main article title."""
        return (
            f'<h1 style="font-size:24px;font-weight:bold;color:{self.theme["heading_color"]};'
            f'text-align:center;margin:30px 0 15px 0;padding:0;'
            f'line-height:1.5;letter-spacing:1px;">'
            f'{self._inline_format(title)}</h1>'
        )

    def _style_h2(self, title):
        """Section header with decorative left border."""
        # Check if it's a PART header
        if re.match(r'^(PART|Part)', title, re.IGNORECASE):
            return self._style_part_header(title)

        return (
            f'<h2 style="font-size:18px;font-weight:bold;'
            f'color:{self.theme["heading_color"]};'
            f'margin:35px 0 15px 0;padding:8px 0 8px 15px;'
            f'border-left:4px solid {self.theme["primary"]};'
            f'line-height:1.5;">'
            f'{self._inline_format(title)}</h2>'
        )

    def _style_h3(self, title):
        """Sub-section header."""
        return (
            f'<h3 style="font-size:16px;font-weight:bold;'
            f'color:{self.theme["primary"]};'
            f'margin:25px 0 10px 0;padding:0;'
            f'line-height:1.5;">'
            f'<span style="display:inline-block;width:8px;height:8px;'
            f'background:{self.theme["secondary"]};border-radius:50%;'
            f'margin-right:8px;vertical-align:middle;"></span>'
            f'{self._inline_format(title)}</h3>'
        )

    def _style_h4(self, title):
        """Sub-sub header."""
        return (
            f'<h4 style="font-size:15px;font-weight:600;'
            f'color:{self.theme["heading_color"]};'
            f'margin:20px 0 8px 0;padding:0;'
            f'line-height:1.5;">'
            f'{self._inline_format(title)}</h4>'
        )

    def _style_paragraph(self, text):
        """Regular paragraph."""
        return (
            f'<p style="font-size:15px;color:{self.theme["text_color"]};'
            f'line-height:1.8;letter-spacing:0.5px;'
            f'margin:10px 0;padding:0;">'
            f'{self._inline_format(text)}</p>'
        )

    def _style_blockquote(self, content):
        """Blockquote / highlighted text."""
        return (
            f'<blockquote style="margin:15px 0;padding:12px 15px;'
            f'background:{self.theme["quote_bg"]};'
            f'border-left:3px solid {self.theme["quote_border"]};'
            f'border-radius:0 4px 4px 0;">'
            f'<p style="font-size:14px;color:{self.theme["text_color"]};'
            f'line-height:1.75;margin:0;">'
            f'{self._inline_format(content)}</p></blockquote>'
        )

    def _style_image(self, src, alt=""):
        """Image with rounded corners and caption."""
        return (
            f'<div style="text-align:center;margin:15px 0;">'
            f'<img src="{src}" alt="{alt}" '
            f'style="max-width:100%;border-radius:8px;'
            f'box-shadow:0 2px 8px rgba(0,0,0,0.08);" />'
            f'</div>'
        )

    def _style_hr(self):
        """Horizontal rule / section separator."""
        return (
            f'<div style="text-align:center;margin:25px 0;">'
            f'<span style="display:inline-block;width:40px;height:2px;'
            f'background:{self.theme["primary"]};border-radius:1px;"></span>'
            f'<span style="display:inline-block;width:8px;height:8px;'
            f'background:{self.theme["secondary"]};border-radius:50%;'
            f'margin:0 8px;vertical-align:middle;"></span>'
            f'<span style="display:inline-block;width:40px;height:2px;'
            f'background:{self.theme["primary"]};border-radius:1px;"></span>'
            f'</div>'
        )

    def _style_article_header(self, text):
        """Article number line: '这是抟微科技陪伴你的第XX篇文章'."""
        return (
            f'<p style="font-size:13px;color:{self.theme["end_color"]};'
            f'text-align:center;margin:20px 0 5px 0;'
            f'letter-spacing:0.5px;">{text}</p>'
        )

    def _style_author(self, text):
        """Author line: '作者 ▌抟微科技'."""
        return (
            f'<p style="font-size:13px;color:{self.theme["secondary"]};'
            f'text-align:center;margin:0 0 25px 0;'
            f'letter-spacing:1px;">{self._inline_format(text)}</p>'
        )

    def _style_part_header(self, text):
        """PART.01 style section header."""
        # Extract the part number and text
        match = re.match(r'^(PART|Part)\.?\s*(\d+)(.*)', text, re.IGNORECASE)
        if match:
            prefix = match.group(1).upper()
            number = match.group(2)
            rest = match.group(3).strip().lstrip('-').strip()

            # Build a stylish section header
            return (
                f'<div style="margin:35px 0 20px 0;text-align:center;">'
                f'<div style="display:inline-block;padding:6px 20px;'
                f'background:{self.theme["primary"]};color:#ffffff;'
                f'border-radius:20px;font-size:14px;font-weight:bold;'
                f'letter-spacing:2px;">'
                f'{prefix}.{number}</div>'
                + (f'<div style="font-size:17px;font-weight:bold;'
                   f'color:{self.theme["heading_color"]};margin-top:12px;'
                   f'line-height:1.5;">{self._inline_format(rest)}</div>' if rest else '')
                + f'</div>'
            )

        return self._style_h2(text)

    def _style_section_number(self, number):
        """Large section number like '01', '02'."""
        return (
            f'<div style="text-align:center;margin:25px 0 10px 0;">'
            f'<span style="display:inline-block;font-size:36px;font-weight:bold;'
            f'color:{self.theme["primary"]};line-height:1;'
            f'letter-spacing:2px;">{number}</span>'
            f'</div>'
        )

    def _style_end_marker(self):
        """·END· marker."""
        return (
            f'<div style="text-align:center;margin:30px 0;">'
            f'<span style="display:inline-block;padding:4px 16px;'
            f'border:1px solid {self.theme["end_color"]};'
            f'border-radius:15px;font-size:12px;'
            f'color:{self.theme["end_color"]};letter-spacing:2px;">'
            f'{BRAND["end_marker"]}</span>'
            f'</div>'
        )

    def _style_cta(self, text):
        """Standard CTA paragraph."""
        return (
            f'<div style="margin:20px 0;padding:15px;'
            f'background:{self.theme["cta_bg"]};'
            f'border-radius:8px;">'
            f'<p style="font-size:14px;color:{self.theme["text_color"]};'
            f'line-height:1.8;margin:0;letter-spacing:0.3px;">'
            f'{self._inline_format(text)}</p></div>'
        )

    def _style_contact(self, text):
        """Contact information line."""
        label = ""
        if "地址:" in text or "地址：" in text:
            label = "地址"
            value = re.sub(r'^.*?[：:]\s*', '', text)
        elif "电话:" in text or "电话：" in text:
            label = "电话"
            value = re.sub(r'^.*?[：:]\s*', '', text)
        elif "网址:" in text or "网址：" in text:
            label = "网址"
            value = re.sub(r'^.*?[：:]\s*', '', text)
        elif "邮箱:" in text or "邮箱：" in text:
            label = "邮箱"
            value = re.sub(r'^.*?[：:]\s*', '', text)
        else:
            return self._style_paragraph(text)

        return (
            f'<p style="font-size:14px;color:{self.theme["text_color"]};'
            f'line-height:1.8;margin:5px 0;padding:0;">'
            f'<span style="font-weight:bold;color:{self.theme["primary"]};">'
            f'{label}: </span>'
            f'<span>{self._inline_format(value)}</span></p>'
        )


# ============================================================
# HTML Document Wrapper
# ============================================================

def wrap_html(content, theme_config, title=""):
    """Wrap content in a complete HTML document for preview."""
    return f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{title or '微信公众号文章预览'}</title>
    <style>
        body {{
            max-width: 677px;
            margin: 0 auto;
            padding: 20px;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                         "Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei",
                         sans-serif;
            background: #ffffff;
        }}
        img {{ max-width: 100% !important; height: auto !important; }}
        ol, ul {{ padding-left: 20px; margin: 10px 0; }}
        li {{ font-size: 15px; color: {theme_config["text_color"]};
              line-height: 1.8; margin: 5px 0; }}
    </style>
</head>
<body>
{content}
</body>
</html>"""


# ============================================================
# Main CLI
# ============================================================

def main():
    parser = argparse.ArgumentParser(
        description="Convert Markdown to WeChat Official Account HTML (Tiny Wings brand style)"
    )
    parser.add_argument("input", help="Input Markdown file path")
    parser.add_argument("-o", "--output", help="Output HTML file path")
    parser.add_argument(
        "--theme", choices=list(THEMES.keys()), default="tech",
        help="Article theme (default: tech)"
    )
    parser.add_argument("--clipboard", action="store_true",
                        help="Copy HTML to clipboard instead of writing file")
    parser.add_argument("--fragment", action="store_true",
                        help="Output HTML fragment only (no wrapper, for direct paste to WeChat)")

    args = parser.parse_args()

    # Read input
    input_path = Path(args.input)
    if not input_path.exists():
        print(f"Error: File not found: {args.input}", file=sys.stderr)
        sys.exit(1)

    markdown_text = input_path.read_text(encoding="utf-8")

    # Parse and convert
    converter = MarkdownParser(theme=args.theme)
    content_html = converter.parse(markdown_text)

    # Determine output format
    if args.fragment:
        # Only the body content with inline styles - for direct paste to WeChat editor
        html_output = content_html
    else:
        # Full HTML document for preview
        html_output = wrap_html(content_html, converter.theme, title=input_path.stem)

    # Output
    if args.clipboard:
        try:
            import subprocess
            if sys.platform == "win32":
                subprocess.run(["clip"], input=html_output.encode("utf-16le"), check=True)
            elif sys.platform == "darwin":
                subprocess.run(["pbcopy"], input=html_output.encode("utf-8"), check=True)
            else:
                subprocess.run(["xclip", "-selection", "clipboard"],
                               input=html_output.encode("utf-8"), check=True)
            print("HTML copied to clipboard!")
        except Exception as e:
            print(f"Clipboard copy failed: {e}", file=sys.stderr)
            print("Writing to file instead...")
            if not args.output:
                args.output = str(input_path.with_suffix(".html"))
    else:
        if not args.output:
            args.output = str(input_path.with_suffix(".html"))

    if args.output and not args.clipboard:
        output_path = Path(args.output)
        output_path.write_text(html_output, encoding="utf-8")
        print(f"HTML written to: {args.output}")
        print(f"Theme: {converter.theme['name']} ({args.theme})")
        print(f"Fragment mode: {args.fragment}")

    # Also print a summary
    word_count = len(re.sub(r'<[^>]+>', '', content_html))
    print(f"Content length: ~{word_count} characters")


if __name__ == "__main__":
    main()
