#!/usr/bin/env python3
"""
Generate a DOCX skill report from a skill's SKILL.md.

Usage:
    python3 generate_skill_report_docx.py <skill_name>

Output:
    ~/.hermes/generated/<skill_name>_Skill_Report.docx
"""

import os
import re
import sys
from datetime import date

from docx import Document
from docx.shared import Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH


def find_skill_dir(skill_name: str) -> str | None:
    """Find the skill directory under ~/.hermes/skills/."""
    base = os.path.expanduser("~/.hermes/skills")
    # Direct: skills/<skill_name>/SKILL.md
    direct = os.path.join(base, skill_name, "SKILL.md")
    if os.path.isfile(direct):
        return os.path.dirname(direct)
    # Categorized: skills/<cat>/<skill_name>/SKILL.md
    for cat in os.listdir(base):
        candidate = os.path.join(base, cat, skill_name, "SKILL.md")
        if os.path.isfile(candidate):
            return os.path.dirname(candidate)
    return None


def extract_frontmatter(text: str) -> dict:
    """Parse YAML frontmatter (basic, no PyYAML dependency)."""
    m = re.match(r"^---\s*\n(.*?)\n---", text, re.DOTALL)
    if not m:
        return {}
    raw = m.group(1)
    result = {}
    for line in raw.split("\n"):
        if ":" in line:
            key, _, val = line.partition(":")
            key = key.strip()
            val = val.strip().strip('"').strip("'")
            result[key] = val
    return result


def strip_frontmatter(text: str) -> str:
    return re.sub(r"^---\s*\n.*?\n---\s*\n", "", text, count=1, flags=re.DOTALL)


def parse_sections(md: str) -> list[tuple[str, str, str]]:
    """
    Return list of (heading_level, heading_text, body).
    heading_level is '#' count as string: '##', '###', etc.
    """
    lines = md.split("\n")
    sections = []
    current_heading = None
    current_level = None
    current_body: list[str] = []

    for line in lines:
        hm = re.match(r"^(#{2,4})\s+(.*)", line)
        if hm:
            if current_heading is not None:
                sections.append((current_level, current_heading, "".join(current_body)))
            current_level = hm.group(1)
            current_heading = hm.group(2).strip()
            current_body = []
        else:
            current_body.append(line + "\n")

    if current_heading is not None:
        sections.append((current_level, current_heading, "".join(current_body)))

    return sections


def add_table(doc: Document, headers: list[str], rows: list[list[str]]):
    """Add a styled table to the document."""
    table = doc.add_table(rows=1 + len(rows), cols=len(headers))
    table.style = "Light Grid Accent 1"
    for i, h in enumerate(headers):
        cell = table.rows[0].cells[i]
        cell.text = h
        for p in cell.paragraphs:
            for r in p.runs:
                r.bold = True
    for ri, row_data in enumerate(rows):
        for ci, val in enumerate(row_data):
            table.rows[ri + 1].cells[ci].text = val
    return table


def generate_report(skill_name: str) -> str:
    """Generate the DOCX report and return its path."""
    skill_dir = find_skill_dir(skill_name)
    if not skill_dir:
        print(f"ERROR: Skill '{skill_name}' not found.", file=sys.stderr)
        sys.exit(1)

    md_path = os.path.join(skill_dir, "SKILL.md")
    with open(md_path) as f:
        raw_md = f.read()

    front = extract_frontmatter(raw_md)
    body_md = strip_frontmatter(raw_md)
    sections = parse_sections(body_md)

    doc = Document()

    # Default style
    style = doc.styles["Normal"]
    style.font.name = "Calibri"
    style.font.size = Pt(10.5)

    # ─── Title ───
    title = front.get("name", skill_name)
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run(title)
    run.bold = True
    run.font.size = Pt(16)
    run.font.color.rgb = RGBColor(0x1F, 0x4E, 0x79)

    desc = front.get("description", "")
    if desc:
        p = doc.add_paragraph()
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        run = p.add_run(desc)
        run.font.size = Pt(9)
        run.font.color.rgb = RGBColor(0x55, 0x55, 0x55)

    doc.add_paragraph("─" * 75)

    p = doc.add_paragraph()
    run = p.add_run(date.today().strftime("%d %B %Y"))
    run.font.size = Pt(9)
    run.font.color.rgb = RGBColor(0x88, 0x88, 0x88)

    # ─── 1. Skill Overview ───
    doc.add_heading("1. Skill Overview", level=1)
    doc.add_heading("1.1 Name", level=2)
    doc.add_paragraph(title)

    doc.add_heading("1.2 Description", level=2)
    doc.add_paragraph(desc)

    # Purpose from body
    purpose = ""
    for level, heading, body in sections:
        if "purpose" in heading.lower() or "scopo" in heading.lower():
            purpose = body.strip()
            break

    if purpose:
        doc.add_heading("1.3 Purpose", level=2)
        doc.add_paragraph(purpose)

    # Triggers
    triggers = []
    if "triggers" in front:
        raw_t = front["triggers"]
        triggers = [t.strip().strip('"').strip("'") for t in raw_t.split(",")]

    doc.add_heading("1.4 Triggers", level=2)
    if triggers:
        for t in triggers:
            doc.add_paragraph(t, style="List Bullet")
    else:
        doc.add_paragraph("(No triggers defined in frontmatter)")

    # ─── 2. Inputs Required ───
    doc.add_heading("2. Inputs Required", level=1)
    input_rows = []
    for level, heading, body in sections:
        if "input" in heading.lower() or "parametri" in heading.lower():
            for line in body.split("\n"):
                line = line.strip().strip("*").strip("-")
                if line.startswith("**") and "**" in line[2:]:
                    parts = line.split("**", 2)
                    param = parts[0].strip("*").strip()
                    rest = parts[2] if len(parts) > 2 else ""
                    # Determine if required or optional
                    req = "Richiesto" if "richiesto" in rest.lower() or "required" in rest.lower() else "Opzionale"
                    desc = rest.split("—")[-1].strip() if "—" in rest else rest.strip()
                    input_rows.append([param, req, desc[:100]])
    if input_rows:
        add_table(doc, ["Parametro", "Obbligo", "Descrizione"], input_rows)
    else:
        doc.add_paragraph("(Vedi sezione Input nel corpo della skill)")

    # ─── 3. Workflow ───
    doc.add_heading("3. Workflow", level=1)
    workflow_rows = []
    for level, heading, body in sections:
        if "workflow" in heading.lower() or "flusso" in heading.lower():
            lines = [l.strip() for l in body.split("\n") if l.strip() and not l.strip().startswith("```")]
            step_num = 1
            for line in lines:
                if line and line[0].isdigit() and "." in line[:4]:
                    parts = line.split(".", 1)
                    desc = parts[1].strip()
                    workflow_rows.append([f"{step_num}. {parts[0]}", desc[:120]])
                    step_num += 1
            if not workflow_rows:
                for line in lines:
                    if line.startswith("-") or line.startswith("*"):
                        workflow_rows.append([str(step_num), line.lstrip("-* ").strip()[:120]])
                        step_num += 1
    if workflow_rows:
        add_table(doc, ["Step", "Descrizione"], workflow_rows)
    else:
        # Fallback: show sections as workflow
        for level, heading, body in sections:
            doc.add_paragraph(f"{heading}: {body.strip()[:200]}")

    # ─── 4. Outputs ───
    doc.add_heading("4. Outputs", level=1)
    found_output = False
    for level, heading, body in sections:
        if "output" in heading.lower():
            doc.add_paragraph(body.strip())
            found_output = True
            break
    if not found_output:
        doc.add_paragraph("Script per Google Earth Engine Code Editor. Fare riferimento alla SKILL.md per i dettagli.")

    # ─── 5. Technical Specifications ───
    doc.add_heading("5. Technical Specifications", level=1)
    spec_rows = []
    # Try to extract technical specs from frontmatter or body
    for level, heading, body in sections:
        if "spec" in heading.lower() or "technical" in heading.lower() or "tecnich" in heading.lower():
            for line in body.split("\n"):
                line = line.strip()
                if "—" in line or "|" in line:
                    parts = [p.strip() for p in line.replace("|", "—").split("—") if p.strip()]
                    if len(parts) >= 2:
                        spec_rows.append([parts[0], "—".join(parts[1:]).strip()[:100]])

    if not spec_rows:
        # Try simple key: value pairs from sections
        for level, heading, body in sections:
            for line in body.split("\n"):
                line = line.strip().strip("|")
                if ":" in line and not line.startswith("```"):
                    parts = line.split(":", 1)
                    k, v = parts[0].strip().strip("**"), parts[1].strip().strip("**")
                    if k and v and len(k) < 30 and len(v) < 120:
                        spec_rows.append([k, v])

    if spec_rows:
        add_table(doc, ["Parametro", "Valore"], spec_rows[:20])
    else:
        doc.add_paragraph("(Vedi SKILL.md per le specifiche tecniche complete)")

    # ─── 6. Version History ───
    doc.add_heading("6. Version History", level=1)
    version = front.get("version", "1.0.0")
    today = date.today().strftime("%d %B %Y")
    add_table(doc, ["Versione", "Data", "Modifiche"], [
        [f"v{version}", today, "Versione corrente del report"],
    ])

    # ─── Footer ───
    doc.add_paragraph("─" * 75)
    p = doc.add_paragraph()
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = p.add_run(f"Document generated by Hermes Agent • Skill Report: {skill_name} • {today}")
    run.font.size = Pt(8)
    run.font.color.rgb = RGBColor(0x88, 0x88, 0x88)

    # ─── Save ───
    out_dir = os.path.expanduser("~/.hermes/generated")
    os.makedirs(out_dir, exist_ok=True)
    out_path = os.path.join(out_dir, f"{skill_name}_Skill_Report.docx")
    doc.save(out_path)
    print(out_path)
    return out_path


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python3 generate_skill_report_docx.py <skill_name>", file=sys.stderr)
        sys.exit(1)
    generate_report(sys.argv[1])
