"""
Jira Export Helper — Standalone script to export Jira tickets to CSV.

Works independently of TestIntel. Only requires httpx and a Jira API token.

Usage:
    # Export specific tickets
    python jira_export.py --url https://yourorg.atlassian.net --tickets HR-1,HR-6,HR-8

    # Export all tickets in a project
    python jira_export.py --url https://yourorg.atlassian.net --project HR

    # Export with JQL
    python jira_export.py --url https://yourorg.atlassian.net --jql "project = HR AND type = Bug"

    # Export from a specific workspace/project on a multi-workspace Jira instance
    python jira_export.py --url https://yourorg.atlassian.net --project TEAM1 --output team1-tickets.csv
    python jira_export.py --url https://yourorg.atlassian.net --project TEAM2 --output team2-tickets.csv

    # Filter by type, status, or sprint
    python jira_export.py --url https://yourorg.atlassian.net --project HR --type Story
    python jira_export.py --url https://yourorg.atlassian.net --project HR --status "In Progress"
    python jira_export.py --url https://yourorg.atlassian.net --project HR --sprint current

Environment variables:
    JIRA_EMAIL       — your Jira account email
    JIRA_API_TOKEN   — API token from https://id.atlassian.com/manage-profile/security/api-tokens

Install dependency:
    pip install httpx
"""
# Copyright (c) 2026 OctoBlue Technologies LLC. All rights reserved.
# Proprietary and confidential. See LICENSE for terms.


import os
import sys
import csv
import argparse
import httpx


def main():
    parser = argparse.ArgumentParser(description="Export Jira tickets to CSV for use with TestIntel")
    parser.add_argument("--url", required=True, help="Jira instance URL (e.g. https://yourorg.atlassian.net)")
    parser.add_argument("--email", default=None, help="Jira email. Defaults to JIRA_EMAIL env var.")
    parser.add_argument("--token", default=None, help="Jira API token. Defaults to JIRA_API_TOKEN env var.")
    parser.add_argument("--tickets", default=None, help="Comma-separated ticket keys (e.g. HR-1,HR-6,HR-8)")
    parser.add_argument("--project", default=None, help="Jira project key (e.g. HR)")
    parser.add_argument("--jql", default=None, help="Custom JQL query")
    parser.add_argument("--type", default=None, help="Filter by issue type (Story, Bug, Task)")
    parser.add_argument("--status", default=None, help="Filter by status")
    parser.add_argument("--sprint", default=None, help="Sprint name or 'current' for open sprints")
    parser.add_argument("--max", type=int, default=100, help="Maximum number of issues to export (default: 100)")
    parser.add_argument("--output", "-o", default="jira-export.csv", help="Output CSV file path (default: jira-export.csv)")
    args = parser.parse_args()

    email = args.email or os.environ.get("JIRA_EMAIL")
    token = args.token or os.environ.get("JIRA_API_TOKEN")

    if not email or not token:
        print("Error: Jira credentials required.")
        print("  Set JIRA_EMAIL and JIRA_API_TOKEN environment variables, or use --email and --token flags.")
        print("  Generate a token at: https://id.atlassian.com/manage-profile/security/api-tokens")
        sys.exit(1)

    base_url = args.url.rstrip("/")
    auth = (email, token)
    headers = {"Accept": "application/json", "Content-Type": "application/json"}

    # Build issue list
    if args.tickets:
        keys = [k.strip() for k in args.tickets.split(",")]
        print(f"Fetching {len(keys)} specific tickets...")
        issues = [fetch_issue(base_url, auth, headers, k) for k in keys]
        issues = [i for i in issues if i]  # filter failures
    else:
        jql = args.jql
        if not jql:
            if not args.project:
                print("Error: --project or --jql or --tickets is required.")
                sys.exit(1)
            parts = [f"project = {args.project}"]
            if args.type:
                parts.append(f"issuetype = '{args.type}'")
            if args.status:
                parts.append(f"status = '{args.status}'")
            if args.sprint:
                if args.sprint.lower() == "current":
                    parts.append("sprint in openSprints()")
                else:
                    parts.append(f"sprint = '{args.sprint}'")
            jql = " AND ".join(parts) + " ORDER BY created DESC"

        print(f"Searching: {jql}")
        issues = search_issues(base_url, auth, headers, jql, args.max)

    if not issues:
        print("No issues found.")
        sys.exit(0)

    # Write CSV
    write_csv(issues, args.output)
    print(f"\nExported {len(issues)} issues to {args.output}")


def fetch_issue(base_url, auth, headers, key):
    try:
        resp = httpx.get(f"{base_url}/rest/api/3/issue/{key}", auth=auth, headers=headers, timeout=15)
        resp.raise_for_status()
        return resp.json()
    except Exception as e:
        print(f"  Warning: failed to fetch {key}: {e}")
        return None


def search_issues(base_url, auth, headers, jql, max_results):
    issues = []
    try:
        resp = httpx.post(
            f"{base_url}/rest/api/3/search/jql",
            auth=auth, headers=headers, timeout=15,
            json={"jql": jql, "maxResults": max_results},
        )
        resp.raise_for_status()
        data = resp.json()
        ids = [item["id"] for item in data.get("issues", [])]
        print(f"Found {len(ids)} issues, fetching details...")
        for issue_id in ids:
            issue = fetch_issue(base_url, auth, headers, issue_id)
            if issue:
                issues.append(issue)
    except Exception as e:
        print(f"Search error: {e}")
    return issues


def extract_text(desc):
    """Extract plain text from Jira ADF or plain string."""
    if not desc:
        return ""
    if isinstance(desc, str):
        return desc
    if isinstance(desc, dict) and "content" in desc:
        return walk_adf(desc)
    return str(desc)


def walk_adf(node):
    if node.get("type") == "text":
        return node.get("text", "")
    parts = []
    for child in node.get("content", []):
        parts.append(walk_adf(child))
    return " ".join(parts).strip()


def nested(fields, key, subkey):
    val = fields.get(key)
    if isinstance(val, dict):
        return val.get(subkey, "")
    return str(val) if val else ""


def write_csv(issues, output_path):
    with open(output_path, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow([
            "Issue Key", "Summary", "Issue Type", "Priority", "Status",
            "Labels", "Description", "Acceptance Criteria",
            "Assignee", "Reporter", "Created", "Updated",
        ])
        for issue in issues:
            fields = issue.get("fields", {})
            desc = extract_text(fields.get("description"))

            # Try to extract acceptance criteria
            ac = ""
            for key, val in fields.items():
                if "acceptance" in key.lower() or "criteria" in key.lower():
                    ac = extract_text(val) if isinstance(val, dict) else str(val or "")
                    break
            if not ac and "acceptance criteria" in desc.lower():
                idx = desc.lower().index("acceptance criteria")
                ac = desc[idx:].strip()

            writer.writerow([
                issue.get("key", ""),
                fields.get("summary", ""),
                nested(fields, "issuetype", "name"),
                nested(fields, "priority", "name"),
                nested(fields, "status", "name"),
                ", ".join(fields.get("labels", [])),
                desc,
                ac,
                nested(fields, "assignee", "displayName"),
                nested(fields, "reporter", "displayName"),
                fields.get("created", ""),
                fields.get("updated", ""),
            ])


if __name__ == "__main__":
    main()
