#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.10"
# dependencies = []
# ///
"""
clickup_export.py — write a ClickUp-importable CSV from product tickets.

Usage:
    uv run clickup_export.py '<json_string>'
    uv run clickup_export.py '<json_string>' <output_dir>

Output: <output_dir>/clickup_import_<project_name>.csv  (output_dir defaults to
the current working directory). See references/clickup_csv_format.md for the
input JSON schema and the ClickUp column mapping.

The CSV is written with the standard library `csv` module so that Markdown
descriptions containing commas and newlines are correctly quoted/escaped —
ClickUp's importer reads RFC-4180 quoted fields, so this round-trips cleanly.
"""

import csv
import json
import os
import sys

# ClickUp import columns, in order. Task Name + Description map from the brief;
# Tags / Due Date / Status are the operational fields collected in phase 3.
COLUMNS = ["Task Name", "Description", "Tags", "Due Date", "Status"]


def build_rows(tickets):
    rows = []
    for i, t in enumerate(tickets):
        name = (t.get("task_name") or "").strip()
        if not name:
            print(f"Ticket #{i + 1} is missing 'task_name'.", file=sys.stderr)
            sys.exit(1)
        rows.append(
            {
                "Task Name": name,
                "Description": t.get("description", "") or "",
                "Tags": t.get("tags", "") or "",
                "Due Date": t.get("due_date", "") or "",
                # An omitted status stays an empty cell so ClickUp applies the
                # target List's own default. Lists use "Open" or "Backlog" as
                # often as "To Do", and a status the List does not define makes
                # the import fail.
                "Status": (t.get("status") or "").strip(),
            }
        )
    return rows


# NOTE: intentionally duplicated in
# gantt-chart-generator/scripts/generate_gantt.py. Each skill is an independently
# installable, self-contained `uv run --script` unit, so it can't import a shared
# module without fragile cross-skill path hacks. Keep the two copies in sync if
# the character rules change (the only intended difference is the default name).
def safe_filename(name):
    name = name or "tickets"
    for a, b in ((" ", "_"), ("/", "-"), ("\\", "-"), ("–", "-"), ("—", "-")):
        name = name.replace(a, b)
    return "".join(c for c in name if c.isalnum() or c in "_-")


def generate(data, output_dir="."):
    tickets = data.get("tickets", [])
    if not tickets:
        print("No tickets found in input.", file=sys.stderr)
        sys.exit(1)

    if not os.path.isdir(output_dir):
        print(f"Error: output directory '{output_dir}' does not exist.", file=sys.stderr)
        sys.exit(1)

    rows = build_rows(tickets)
    fname = f"clickup_import_{safe_filename(data.get('project_name'))}.csv"
    output_path = os.path.join(output_dir, fname)

    # newline="" + utf-8-sig: Excel/ClickUp read the BOM, multiline cells stay intact.
    with open(output_path, "w", newline="", encoding="utf-8-sig") as f:
        writer = csv.DictWriter(f, fieldnames=COLUMNS)
        writer.writeheader()
        writer.writerows(rows)

    print(f"Saved: {output_path} ({len(rows)} tickets)")
    return output_path


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: uv run clickup_export.py '<json_string>' [output_dir]")
        sys.exit(1)
    try:
        payload = json.loads(sys.argv[1])
    except json.JSONDecodeError as e:
        print(f"Error: invalid JSON — {e}", file=sys.stderr)
        sys.exit(1)
    out_dir = sys.argv[2] if len(sys.argv) > 2 else "."
    generate(payload, out_dir)
