#!/usr/bin/env python3
"""
DocuSign Template Builder
Creates two templates in the demo environment:
  1. Non-Employee IT Access Form
  2. New Starter IT Access Form

Run: python3 build_templates.py
"""

import os, sys, json, time, base64, requests
import jwt as pyjwt

# ── Config ────────────────────────────────────────────────────────────────────
CLIENT_ID       = "33016b18-9008-4a83-bfdd-be58593465a6"
USER_ID         = "f95937b1-587c-4515-b6c5-1116d32a8922"
ACCOUNT_ID      = "45807776"
BASE_URI        = "https://demo.docusign.net"
AUTH_HOST       = "account-d.docusign.com"
PRIVATE_KEY     = "/home/isthekid/.openclaw/workspace/secrets/docusign_demo_private.key"

FORMS = [
    {
        "name":       "Non-Employee IT Access Form",
        "pdf":        "/home/isthekid/.openclaw/workspace/forms/Non-Employee_IT_Access_Form_2026-02-22.pdf",
        "templateId": "62d150fd-8b88-4413-a71b-4df06a2cc0c5",
    },
    {
        "name":       "New Starter IT Access Form",
        "pdf":        "/home/isthekid/.openclaw/workspace/forms/New_Starter_IT_Access_Form_2026-02-22.pdf",
        "templateId": "6eeb8263-8d88-4bd7-a4f2-6342b84fc5c2",
    },
]

# ── Auth ──────────────────────────────────────────────────────────────────────
def get_access_token():
    with open(PRIVATE_KEY) as f:
        pk = f.read()
    now = int(time.time())
    payload = {
        "iss": CLIENT_ID,
        "sub": USER_ID,
        "aud": AUTH_HOST,
        "iat": now,
        "exp": now + 3600,
        "scope": "signature impersonation",
    }
    token = pyjwt.encode(payload, pk, algorithm="RS256")
    resp = requests.post(
        f"https://{AUTH_HOST}/oauth/token",
        data={"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": token},
    )
    resp.raise_for_status()
    return resp.json()["access_token"]


# ── Tab builders ──────────────────────────────────────────────────────────────
#
# Coordinate system: fitz (pymupdf) uses top-left origin (same as DocuSign).
# All positions below are taken directly from the PDF widget rects.
# Page is 612 x 792 pts (letter).

def requester_tabs():
    return {

        # ── Date pickers ──────────────────────────────────────────────────────
        "dateTabs": [
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "StartDate",
                "xPosition": "41",  "yPosition": "135",
                "width": "127", "height": "17",
                "required": "true",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "EndDate",
                "xPosition": "42",  "yPosition": "235",
                "width": "150", "height": "22",
                "required": "false",
            },
        ],

        # ── Text fields ───────────────────────────────────────────────────────
        "textTabs": [
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "FirstName",
                "xPosition": "176", "yPosition": "136",
                "width": "205", "height": "17",
                "required": "true",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "LastName",
                "xPosition": "391", "yPosition": "136",
                "width": "179", "height": "17",
                "required": "true",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "PreferredName",
                "xPosition": "41",  "yPosition": "170",
                "width": "340", "height": "17",
                "required": "false",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "Employer",
                "xPosition": "391", "yPosition": "170",
                "width": "179", "height": "17",
                "required": "true",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "Manager",
                "xPosition": "41",  "yPosition": "203",
                "width": "340", "height": "17",
                "required": "true",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "TitlePosition",
                "xPosition": "391", "yPosition": "203",
                "width": "179", "height": "17",
                "required": "true",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "MirrorAccountAccess",
                "xPosition": "41",  "yPosition": "320",
                "width": "529", "height": "17",
                "required": "false",
            },
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "SharePointAccess",
                "xPosition": "314", "yPosition": "453",
                "width": "252", "height": "22",
                "required": "false",
            },
        ],

        # ── Checkboxes (software) ─────────────────────────────────────────────
        "checkboxTabs": [
            {"documentId": "1", "pageNumber": "1", "tabLabel": "SAP",
             "xPosition": "41",  "yPosition": "365"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "AdobePro",
             "xPosition": "41",  "yPosition": "387"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "Zoom",
             "xPosition": "41",  "yPosition": "410"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "EFax",
             "xPosition": "41",  "yPosition": "433"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "VPN",
             "xPosition": "41",  "yPosition": "457"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "BoxCom",
             "xPosition": "171", "yPosition": "364"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "GoToMyPC",
             "xPosition": "171", "yPosition": "386"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "MSCoPilot",
             "xPosition": "171", "yPosition": "410"},
            {"documentId": "1", "pageNumber": "1", "tabLabel": "ChatGPTEnt",
             "xPosition": "172", "yPosition": "434"},
        ],

        # ── Radio groups ──────────────────────────────────────────────────────
        "radioGroupTabs": [
            # Default Domain (@Bertelsmann.com / @versidi.com / @bhi.vc)
            {
                "documentId": "1",
                "groupName": "DefaultDomain",
                "requireInitialOnSharedChange": False,
                "radios": [
                    {"pageNumber": "1", "xPosition": "37",  "yPosition": "290",
                     "value": "@Bertelsmann.com", "selected": "false", "required": "true"},
                    {"pageNumber": "1", "xPosition": "143", "yPosition": "290",
                     "value": "@versidi.com",     "selected": "false", "required": "true"},
                    {"pageNumber": "1", "xPosition": "226", "yPosition": "290",
                     "value": "@bhi.vc",          "selected": "false", "required": "true"},
                ],
            },
            # Computer Needed? (Y / N)
            {
                "documentId": "1",
                "groupName": "ComputerNeeded",
                "requireInitialOnSharedChange": False,
                "radios": [
                    {"pageNumber": "1", "xPosition": "518", "yPosition": "363",
                     "value": "Y", "selected": "false", "required": "false"},
                    {"pageNumber": "1", "xPosition": "544", "yPosition": "364",
                     "value": "N", "selected": "false", "required": "false"},
                ],
            },
            # MS Teams Number? (Y / N)
            {
                "documentId": "1",
                "groupName": "MSTeamsNumber",
                "requireInitialOnSharedChange": False,
                "radios": [
                    {"pageNumber": "1", "xPosition": "517", "yPosition": "383",
                     "value": "Y", "selected": "false", "required": "false"},
                    {"pageNumber": "1", "xPosition": "544", "yPosition": "383",
                     "value": "N", "selected": "false", "required": "false"},
                ],
            },
            # Cell Phone Plan? (Y / N)
            {
                "documentId": "1",
                "groupName": "CellPhonePlan",
                "requireInitialOnSharedChange": False,
                "radios": [
                    {"pageNumber": "1", "xPosition": "517", "yPosition": "403",
                     "value": "Y", "selected": "false", "required": "false"},
                    {"pageNumber": "1", "xPosition": "544", "yPosition": "402",
                     "value": "N", "selected": "false", "required": "false"},
                ],
            },
        ],

        # ── Signature + date signed ───────────────────────────────────────────
        # Coordinates confirmed by Adner directly from DocuSign template editor (2026-02-22)
        # Sign:        x=173, y=507
        # Date Signed: x=434, y=520
        "signHereTabs": [
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "RequesterSignature",
                "xPosition": "173", "yPosition": "507",
            },
        ],
        "dateSignedTabs": [
            {
                "documentId": "1", "pageNumber": "1",
                "tabLabel": "RequesterDateSigned",
                "xPosition": "434", "yPosition": "520",
            },
        ],
    }


def it_admin_tabs():
    """IT Admin is CC — receives a completed copy, no signature required."""
    return {}


# ── Template creator / updater ────────────────────────────────────────────────
def update_template(access_token, template_id, name, pdf_path):
    """PUT to update an existing template in-place."""
    with open(pdf_path, "rb") as f:
        pdf_b64 = base64.b64encode(f.read()).decode()

    body = build_template_body(name, pdf_b64)
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
    url = f"{BASE_URI}/restapi/v2.1/accounts/{ACCOUNT_ID}/templates/{template_id}"
    resp = requests.put(url, headers=headers, json=body)
    return resp


def build_template_body(name, pdf_b64):
    return {
        "name": name,
        "description": f"{name} — built by Mr Anderson 2026-02-22",
        "documents": [
            {
                "documentId": "1",
                "name": f"{name}.pdf",
                "documentBase64": pdf_b64,
                "transformPdfFields": False,
            }
        ],
        "recipients": {
            "signers": [
                {
                    "roleName": "Requester/Manager",
                    "recipientId": "1",
                    "routingOrder": "1",
                    "tabs": requester_tabs(),
                },
            ],
            "carbonCopies": [
                {
                    "roleName": "IT Admin",
                    "recipientId": "2",
                    "routingOrder": "2",
                },
            ],
        },
    }


def create_template(access_token, name, pdf_path):
    with open(pdf_path, "rb") as f:
        pdf_b64 = base64.b64encode(f.read()).decode()

    body = build_template_body(name, pdf_b64)
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
    url = f"{BASE_URI}/restapi/v2.1/accounts/{ACCOUNT_ID}/templates"
    resp = requests.post(url, headers=headers, json=body)
    return resp


def delete_template(access_token, template_id):
    """Delete an existing template by ID."""
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Accept": "application/json",
    }
    url = f"{BASE_URI}/restapi/v2.1/accounts/{ACCOUNT_ID}/templates/{template_id}"
    return requests.delete(url, headers=headers)


# ── Main ──────────────────────────────────────────────────────────────────────
def main():
    print("Getting access token...")
    try:
        token = get_access_token()
        print("  ✅ Token acquired")
    except Exception as e:
        print(f"  ❌ Auth failed: {e}")
        sys.exit(1)

    results = []
    for form in FORMS:
        tid = form.get("templateId")

        # Delete existing template first to avoid tab accumulation
        if tid:
            print(f"\nDeleting existing template: {form['name']!r} ({tid})")
            del_resp = delete_template(token, tid)
            if del_resp.status_code in (200, 204):
                print(f"  ✅ Deleted")
            else:
                print(f"  ⚠️  Delete returned {del_resp.status_code}: {del_resp.text[:200]}")

        # Recreate fresh
        print(f"  Creating fresh: {form['name']!r}")
        resp = create_template(token, form["name"], form["pdf"])

        if resp.status_code in (200, 201):
            data = resp.json()
            new_tid = data.get("templateId", "?")
            print(f"  ✅ Created — templateId: {new_tid}")
            results.append({"name": form["name"], "templateId": new_tid, "status": "recreated"})
        else:
            print(f"  ❌ Failed ({resp.status_code}): {resp.text[:500]}")
            results.append({"name": form["name"], "status": "error", "detail": resp.text[:500]})

    # Save results
    out = "/home/isthekid/.openclaw/workspace/docusign/template_ids.json"
    with open(out, "w") as f:
        json.dump(results, f, indent=2)
    print(f"\nResults written to {out}")
    return results


if __name__ == "__main__":
    main()
