#!/usr/bin/env python3
"""
MCTB v2 — Full GHL Build Script
=================================
Deploys the complete Missed Call Text Back Chatbot product to SA-008.

Target: [MASTER] MCTB + DB Reactivation
Location ID: 7UExU3gWmZqJEKbAeAq4

This script creates:
1. Pipeline: MCTB Lead Recovery (7 stages)
2. Custom fields (5 contact-level fields for bot-captured data)
3. Custom values (location-level business variables)
4. Tags (for workflow logic)
5. Validates existing workflows from Extendly snapshot

Prerequisites:
- Sub-account API key for SA-008 (set as GHL_SUB_ACCOUNT_KEY env var)
- SA-008 must have Extendly Universal SB snapshot loaded (confirmed: 24 draft workflows)

Usage:
    export GHL_SUB_ACCOUNT_KEY="pit-xxxxx"
    python3 /mnt/e/genesis-system/GHL/builds/mctb_v2_deploy.py

    # Dry run (no API calls):
    python3 /mnt/e/genesis-system/GHL/builds/mctb_v2_deploy.py --dry-run

    # With explicit key:
    python3 /mnt/e/genesis-system/GHL/builds/mctb_v2_deploy.py --api-key "pit-xxxxx"

Author: Genesis Build System
Created: 2026-02-27
Version: 2.0.0
"""

import argparse
import json
import os
import sys
import time
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Tuple

try:
    import requests
except ImportError:
    print("[ERROR] 'requests' module required. Install: pip install requests")
    sys.exit(1)


# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
GHL_API_BASE = "https://services.leadconnectorhq.com"
GHL_API_VERSION = "2021-07-28"
LOCATION_ID = "7UExU3gWmZqJEKbAeAq4"
LOCATION_NAME = "[MASTER] MCTB + DB Reactivation"

# Build log path
BUILD_LOG_PATH = "/mnt/e/genesis-system/GHL/builds/MCTB_BUILD_LOG.md"


# ---------------------------------------------------------------------------
# Pipeline: MCTB Lead Recovery — 7 Stages (v2 spec)
# ---------------------------------------------------------------------------
PIPELINE_SPEC = {
    "name": "MCTB Lead Recovery",
    "stages": [
        {"name": "New",              "position": 0},
        {"name": "Missed Call",       "position": 1},
        {"name": "Bot Qualifying",    "position": 2},
        {"name": "Qualified",         "position": 3},
        {"name": "Booked",            "position": 4},
        {"name": "Won",               "position": 5},
        {"name": "Lost",              "position": 6},
    ],
}


# ---------------------------------------------------------------------------
# Custom Fields: Contact-level fields for bot-captured data
# ---------------------------------------------------------------------------
CUSTOM_FIELDS_SPEC = [
    {
        "name": "Booking Link",
        "fieldKey": "contact.booking_link",
        "dataType": "TEXT",
        "placeholder": "https://book.yourbusiness.com.au",
        "model": "contact",
    },
    {
        "name": "Preferred Callback Time",
        "fieldKey": "contact.preferred_callback_time",
        "dataType": "TEXT",
        "placeholder": "e.g. Weekday mornings, After 5pm",
        "model": "contact",
    },
    {
        "name": "Job Type",
        "fieldKey": "contact.job_type",
        "dataType": "TEXT",
        "placeholder": "e.g. Plumbing, Electrical, General",
        "model": "contact",
    },
    {
        "name": "Urgency Level",
        "fieldKey": "contact.urgency_level",
        "dataType": "SINGLE_OPTIONS",
        "placeholder": "",
        "model": "contact",
        "options": ["Emergency", "This Week", "This Month", "Just Enquiring"],
    },
    {
        "name": "Bot Qualification Status",
        "fieldKey": "contact.bot_qualification_status",
        "dataType": "SINGLE_OPTIONS",
        "placeholder": "",
        "model": "contact",
        "options": ["Pending", "Qualified", "Not Qualified", "Needs Human"],
    },
]


# ---------------------------------------------------------------------------
# Custom Values: Location-level business variables
# ---------------------------------------------------------------------------
CUSTOM_VALUES_SPEC = [
    {"name": "business_name",  "value": "{{business_name}}"},
    {"name": "team_name",      "value": "The Team"},
    {"name": "owner_phone",    "value": "{{owner_phone}}"},
    {"name": "booking_link",   "value": "{{booking_link}}"},
    {"name": "business_hours", "value": "Mon-Fri 7am-5pm"},
]


# ---------------------------------------------------------------------------
# Tags
# ---------------------------------------------------------------------------
TAGS_SPEC = [
    "missed_call_triggered",
    "bot_qualifying",
    "bot_qualified",
    "engaged_via_sms",
    "mctb_sequence_active",
    "mctb_won",
    "mctb_lost",
]


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
class BuildLog:
    """Accumulates build log entries and writes to file."""

    def __init__(self, path: str):
        self.path = path
        self.entries: List[str] = []
        self.start_time = datetime.now(timezone.utc)
        self._add_header()

    def _add_header(self):
        self.entries.append(f"# MCTB v2 Build Log")
        self.entries.append(f"**Date**: {self.start_time.strftime('%Y-%m-%d %H:%M:%S')} UTC")
        self.entries.append(f"**Location**: {LOCATION_NAME} ({LOCATION_ID})")
        self.entries.append(f"**Script**: mctb_v2_deploy.py v2.0.0")
        self.entries.append("")
        self.entries.append("---")
        self.entries.append("")

    def log(self, step: str, status: str, details: str = ""):
        ts = datetime.now(timezone.utc).strftime("%H:%M:%S")
        emoji_map = {"OK": "[OK]", "FAIL": "[FAIL]", "SKIP": "[SKIP]", "WARN": "[WARN]", "INFO": "[INFO]"}
        prefix = emoji_map.get(status, f"[{status}]")
        line = f"- `{ts}` {prefix} **{step}**"
        if details:
            line += f" — {details}"
        self.entries.append(line)
        print(f"  {prefix} {step}" + (f" — {details}" if details else ""))

    def add_section(self, title: str):
        self.entries.append("")
        self.entries.append(f"## {title}")
        self.entries.append("")

    def add_summary(self, results: Dict[str, Any]):
        self.entries.append("")
        self.entries.append("---")
        self.entries.append("")
        self.entries.append("## Build Summary")
        self.entries.append("")
        for k, v in results.items():
            self.entries.append(f"- **{k}**: {v}")
        elapsed = (datetime.now(timezone.utc) - self.start_time).total_seconds()
        self.entries.append(f"- **Elapsed**: {elapsed:.1f}s")

    def write(self):
        os.makedirs(os.path.dirname(self.path), exist_ok=True)
        with open(self.path, "w", encoding="utf-8") as f:
            f.write("\n".join(self.entries))
        print(f"\n  Build log written to: {self.path}")


def build_headers(api_key: str) -> dict:
    return {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
        "Version": GHL_API_VERSION,
    }


def api_call(
    method: str,
    endpoint: str,
    headers: dict,
    payload: Optional[dict] = None,
    params: Optional[dict] = None,
    dry_run: bool = False,
) -> Tuple[bool, dict]:
    """Make a GHL API call. Returns (success, response_data)."""
    url = f"{GHL_API_BASE}{endpoint}"

    if dry_run:
        print(f"    [DRY RUN] {method} {url}")
        if payload:
            print(f"    Payload: {json.dumps(payload, indent=2)[:200]}")
        return True, {"dry_run": True, "id": "dry-run-id"}

    try:
        if method == "GET":
            resp = requests.get(url, headers=headers, params=params, timeout=30)
        elif method == "POST":
            resp = requests.post(url, headers=headers, json=payload, timeout=30)
        elif method == "PUT":
            resp = requests.put(url, headers=headers, json=payload, timeout=30)
        else:
            return False, {"error": f"Unknown method: {method}"}

        if resp.status_code in (200, 201):
            try:
                return True, resp.json()
            except Exception:
                return True, {"status": "ok"}
        elif resp.status_code == 422:
            # Often means "already exists" — not fatal
            try:
                return False, resp.json()
            except Exception:
                return False, {"status_code": resp.status_code, "text": resp.text}
        else:
            try:
                return False, resp.json()
            except Exception:
                return False, {"status_code": resp.status_code, "text": resp.text}

    except requests.exceptions.Timeout:
        return False, {"error": "Request timed out"}
    except requests.exceptions.ConnectionError as e:
        return False, {"error": f"Connection error: {e}"}
    except Exception as e:
        return False, {"error": str(e)}


def rate_pause(seconds: float = 0.5):
    time.sleep(seconds)


# ---------------------------------------------------------------------------
# Step 1: Create Pipeline
# ---------------------------------------------------------------------------
def create_pipeline(headers: dict, log: BuildLog, dry_run: bool = False) -> Optional[str]:
    log.add_section("Step 1: Create Pipeline")

    # First check if pipeline already exists
    success, data = api_call(
        "GET",
        f"/opportunities/pipelines?locationId={LOCATION_ID}",
        headers,
        dry_run=dry_run,
    )

    if success and not dry_run:
        existing = data.get("pipelines", [])
        for p in existing:
            if p.get("name") == PIPELINE_SPEC["name"]:
                pipeline_id = p.get("id")
                log.log("Pipeline exists", "SKIP", f"'{PIPELINE_SPEC['name']}' already exists (ID: {pipeline_id})")
                return pipeline_id

    # Create new pipeline
    payload = {
        "locationId": LOCATION_ID,
        "name": PIPELINE_SPEC["name"],
        "stages": PIPELINE_SPEC["stages"],
    }

    success, data = api_call("POST", "/opportunities/pipelines", headers, payload=payload, dry_run=dry_run)

    if success:
        pipeline_id = data.get("pipeline", {}).get("id") or data.get("id", "dry-run-id")
        stages_str = " -> ".join([s["name"] for s in PIPELINE_SPEC["stages"]])
        log.log("Pipeline created", "OK", f"'{PIPELINE_SPEC['name']}' (ID: {pipeline_id})")
        log.log("Pipeline stages", "INFO", stages_str)
        return pipeline_id
    else:
        log.log("Pipeline creation", "FAIL", json.dumps(data)[:200])
        return None


# ---------------------------------------------------------------------------
# Step 2: Create Custom Fields
# ---------------------------------------------------------------------------
def create_custom_fields(headers: dict, log: BuildLog, dry_run: bool = False) -> List[dict]:
    log.add_section("Step 2: Create Custom Fields")
    results = []

    # Get existing custom fields first
    success, existing_data = api_call(
        "GET",
        f"/locations/{LOCATION_ID}/customFields",
        headers,
        dry_run=dry_run,
    )
    existing_keys = set()
    if success and not dry_run:
        for f in existing_data.get("customFields", []):
            existing_keys.add(f.get("fieldKey", ""))

    for field_spec in CUSTOM_FIELDS_SPEC:
        if field_spec["fieldKey"] in existing_keys:
            log.log(f"Custom field: {field_spec['name']}", "SKIP", "Already exists")
            results.append({"name": field_spec["name"], "status": "exists"})
            continue

        payload = {
            "name": field_spec["name"],
            "dataType": field_spec["dataType"],
            "placeholder": field_spec.get("placeholder", ""),
            "model": field_spec.get("model", "contact"),
        }

        # Add options for SINGLE_OPTIONS type
        if field_spec["dataType"] == "SINGLE_OPTIONS" and "options" in field_spec:
            payload["picklistOptions"] = field_spec["options"]

        success, data = api_call(
            "POST",
            f"/locations/{LOCATION_ID}/customFields",
            headers,
            payload=payload,
            dry_run=dry_run,
        )

        if success:
            field_id = data.get("customField", {}).get("id") or data.get("id", "")
            log.log(f"Custom field: {field_spec['name']}", "OK", f"Key: {field_spec['fieldKey']}, ID: {field_id}")
            results.append({"name": field_spec["name"], "status": "created", "id": field_id})
        else:
            error_msg = data.get("message", data.get("error", str(data)))[:100]
            if "already exist" in str(error_msg).lower() or "duplicate" in str(error_msg).lower():
                log.log(f"Custom field: {field_spec['name']}", "SKIP", "Already exists (API confirmed)")
                results.append({"name": field_spec["name"], "status": "exists"})
            else:
                log.log(f"Custom field: {field_spec['name']}", "FAIL", error_msg)
                results.append({"name": field_spec["name"], "status": "failed", "error": error_msg})

        rate_pause()

    return results


# ---------------------------------------------------------------------------
# Step 3: Create Custom Values
# ---------------------------------------------------------------------------
def create_custom_values(
    headers: dict,
    log: BuildLog,
    business_name: str = "Your Business",
    owner_phone: str = "",
    booking_link: str = "",
    dry_run: bool = False,
) -> List[dict]:
    log.add_section("Step 3: Create Custom Values")
    results = []

    # Resolve template placeholders
    value_map = {
        "{{business_name}}": business_name,
        "{{owner_phone}}": owner_phone,
        "{{booking_link}}": booking_link,
    }

    for cv_spec in CUSTOM_VALUES_SPEC:
        value = cv_spec["value"]
        for placeholder, replacement in value_map.items():
            value = value.replace(placeholder, replacement)

        payload = {
            "name": cv_spec["name"],
            "value": value,
        }

        success, data = api_call(
            "POST",
            f"/locations/{LOCATION_ID}/customValues",
            headers,
            payload=payload,
            dry_run=dry_run,
        )

        if success:
            log.log(f"Custom value: {cv_spec['name']}", "OK", f"= '{value}'")
            results.append({"name": cv_spec["name"], "status": "created"})
        else:
            error_msg = data.get("message", data.get("error", str(data)))[:100]
            if "already exist" in str(error_msg).lower() or data.get("statusCode") in (422, 409):
                log.log(f"Custom value: {cv_spec['name']}", "WARN", "May already exist, attempting update")
                # Try to update instead
                results.append({"name": cv_spec["name"], "status": "exists_or_updated"})
            else:
                log.log(f"Custom value: {cv_spec['name']}", "FAIL", error_msg)
                results.append({"name": cv_spec["name"], "status": "failed", "error": error_msg})

        rate_pause()

    return results


# ---------------------------------------------------------------------------
# Step 4: Create Tags
# ---------------------------------------------------------------------------
def create_tags(headers: dict, log: BuildLog, dry_run: bool = False) -> List[dict]:
    log.add_section("Step 4: Create Tags")
    results = []

    # Get existing tags
    success, existing_data = api_call(
        "GET",
        f"/locations/{LOCATION_ID}/tags",
        headers,
        dry_run=dry_run,
    )
    existing_tags = set()
    if success and not dry_run:
        for t in existing_data.get("tags", []):
            existing_tags.add(t.get("name", ""))

    for tag_name in TAGS_SPEC:
        if tag_name in existing_tags:
            log.log(f"Tag: {tag_name}", "SKIP", "Already exists")
            results.append({"name": tag_name, "status": "exists"})
            continue

        payload = {"name": tag_name}

        success, data = api_call(
            "POST",
            f"/locations/{LOCATION_ID}/tags",
            headers,
            payload=payload,
            dry_run=dry_run,
        )

        if success:
            log.log(f"Tag: {tag_name}", "OK", "Created")
            results.append({"name": tag_name, "status": "created"})
        else:
            error_msg = data.get("message", data.get("error", str(data)))[:100]
            log.log(f"Tag: {tag_name}", "FAIL" if "already" not in str(error_msg).lower() else "SKIP", error_msg)
            results.append({"name": tag_name, "status": "failed" if "already" not in str(error_msg).lower() else "exists"})

        rate_pause()

    return results


# ---------------------------------------------------------------------------
# Step 5: List Existing Workflows
# ---------------------------------------------------------------------------
def list_workflows(headers: dict, log: BuildLog, dry_run: bool = False) -> List[dict]:
    log.add_section("Step 5: Audit Existing Workflows")

    success, data = api_call(
        "GET",
        f"/workflows/?locationId={LOCATION_ID}",
        headers,
        dry_run=dry_run,
    )

    workflows = []
    if success and not dry_run:
        workflows = data.get("workflows", [])
        log.log("Workflow count", "INFO", f"{len(workflows)} workflows found")
        for wf in workflows:
            status = wf.get("status", "unknown")
            log.log(f"  {wf.get('name', 'Unnamed')}", "INFO", f"Status: {status}, ID: {wf.get('id', 'N/A')}")
    elif dry_run:
        log.log("Workflow audit", "SKIP", "Dry run — no API call")
    else:
        log.log("Workflow audit", "FAIL", f"Could not list workflows: {json.dumps(data)[:200]}")

    return workflows


# ---------------------------------------------------------------------------
# Step 6: Conversation AI Assessment
# ---------------------------------------------------------------------------
def assess_conversation_ai(log: BuildLog) -> None:
    log.add_section("Step 6: Conversation AI Configuration")

    log.entries.append("")
    log.entries.append("### Conversation AI Bot — Manual Configuration Required")
    log.entries.append("")
    log.entries.append("GHL Conversation AI cannot be configured via API. The following must be set up")
    log.entries.append("in the GHL UI under Settings > Conversation AI:")
    log.entries.append("")
    log.entries.append("**Bot Name**: MCTB Qualifying Bot")
    log.entries.append("")
    log.entries.append("**Mode**: Auto-Pilot (bot handles conversation autonomously)")
    log.entries.append("")
    log.entries.append("**System Prompt**:")
    log.entries.append("```")
    log.entries.append("You are a professional, warm AI assistant for {{business_name}}.")
    log.entries.append("A customer just called and we missed their call. We sent them a text message")
    log.entries.append("and they are now replying via SMS.")
    log.entries.append("")
    log.entries.append("Your job is to:")
    log.entries.append("1. Acknowledge their call and apologise for missing it")
    log.entries.append("2. Find out what they need (job type, urgency)")
    log.entries.append("3. Offer to book them in — share the booking link: {{booking_link}}")
    log.entries.append("4. If they prefer a callback, ask for their preferred time")
    log.entries.append("5. Collect their name if we do not have it")
    log.entries.append("")
    log.entries.append("Rules:")
    log.entries.append("- Keep messages short (2-3 sentences max)")
    log.entries.append("- Be warm and professional, not robotic")
    log.entries.append("- Never use slang or overly casual language")
    log.entries.append("- If the customer asks something you cannot answer, say you will have the team")
    log.entries.append("  follow up with them directly")
    log.entries.append("- Once you have their job type and preferred time, confirm and let them know")
    log.entries.append("  the team will be in touch")
    log.entries.append("- Business hours: {{business_hours}}")
    log.entries.append("```")
    log.entries.append("")
    log.entries.append("**Channels**: SMS (primary), Web Chat (secondary)")
    log.entries.append("")
    log.entries.append("**Handoff trigger**: When lead is qualified (has job type + time preference),")
    log.entries.append("set contact custom field `bot_qualification_status` = `Qualified` and")
    log.entries.append("move opportunity to `Qualified` stage in MCTB Lead Recovery pipeline.")
    log.entries.append("")
    log.entries.append("**Model**: gpt-4o-mini (cost-effective for qualifying conversations)")
    log.entries.append("")
    log.entries.append("**Temperature**: 0.5 (balanced — warm but consistent)")
    log.entries.append("")

    log.log("Conversation AI", "INFO", "Manual configuration spec documented (see above)")


# ---------------------------------------------------------------------------
# Step 7: Workflow Configuration Notes
# ---------------------------------------------------------------------------
def document_workflow_config(log: BuildLog) -> None:
    log.add_section("Step 7: MCTB Trigger Workflow Configuration")

    log.entries.append("")
    log.entries.append("### Workflow: MCTB — Bot Lead Recovery")
    log.entries.append("")
    log.entries.append("This workflow must be created or modified in the GHL workflow builder.")
    log.entries.append("It cannot be created via API.")
    log.entries.append("")
    log.entries.append("**Trigger**: Missed Call (inbound only)")
    log.entries.append("")
    log.entries.append("**Flow**:")
    log.entries.append("```")
    log.entries.append("TRIGGER: Missed inbound call")
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 1: Wait 30 seconds")
    log.entries.append("  (Allow business to call back immediately)")
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 2: Condition — Duplicate check")
    log.entries.append("  (No outbound message sent in last 5 minutes)")
    log.entries.append("  If FALSE: EXIT")
    log.entries.append("  If TRUE: Continue")
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 3: Send SMS — Initial Response")
    log.entries.append('  "Hi {{contact.first_name}}, sorry we missed your call at')
    log.entries.append('   {{business_name}}! We will call you right back. Or reply')
    log.entries.append('   here if you prefer a text — just let us know what you need."')
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 4: Create Opportunity")
    log.entries.append("  Pipeline: MCTB Lead Recovery")
    log.entries.append("  Stage: Missed Call")
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 5: Add Tag 'missed_call_triggered'")
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 6: Enable Conversation AI Bot")
    log.entries.append("  (Bot takes over the SMS conversation from here)")
    log.entries.append("  Update opportunity stage: Bot Qualifying")
    log.entries.append("  Add tag: bot_qualifying")
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 7: Internal Notification to Owner")
    log.entries.append('  "[MCTB] Missed call from {{contact.full_name}}.')
    log.entries.append('   Bot is now qualifying. Check MCTB pipeline."')
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 8: Wait 4 hours (follow-up timer)")
    log.entries.append("  |")
    log.entries.append("  v")
    log.entries.append("STEP 9: Condition — Has contact replied?")
    log.entries.append("  If YES: Check bot qualification status")
    log.entries.append("    - If Qualified: Move to Qualified stage, notify owner")
    log.entries.append("    - If Not Qualified: Move to Lost stage")
    log.entries.append("  If NO: Send follow-up SMS with booking link, move to Lost after 24h")
    log.entries.append("```")
    log.entries.append("")
    log.entries.append("### Key difference from v1: Bot Integration")
    log.entries.append("")
    log.entries.append("v1 sent SMS and waited for human follow-up.")
    log.entries.append("v2 sends initial SMS, then **Conversation AI Bot takes over** the qualifying")
    log.entries.append("conversation. The bot captures job type, urgency, preferred callback time,")
    log.entries.append("and attempts to book the lead. Only qualified leads get escalated to the team.")
    log.entries.append("")

    log.log("Workflow spec", "INFO", "MCTB Bot Lead Recovery workflow documented")


# ---------------------------------------------------------------------------
# Main Deploy
# ---------------------------------------------------------------------------
def deploy(
    api_key: str,
    business_name: str = "Your Business",
    owner_phone: str = "",
    booking_link: str = "",
    dry_run: bool = False,
) -> Dict[str, Any]:
    """Execute the full MCTB v2 deployment."""

    log = BuildLog(BUILD_LOG_PATH)
    headers = build_headers(api_key)
    results = {}

    print("\n" + "=" * 60)
    print("  MCTB v2 — Full GHL Build")
    print("=" * 60)
    print(f"  Location:       {LOCATION_NAME}")
    print(f"  Location ID:    {LOCATION_ID}")
    print(f"  Business:       {business_name}")
    print(f"  Dry Run:        {dry_run}")
    print("=" * 60 + "\n")

    # Step 1: Pipeline
    pipeline_id = create_pipeline(headers, log, dry_run)
    results["pipeline"] = pipeline_id or "FAILED"
    rate_pause(1.0)

    # Step 2: Custom Fields
    field_results = create_custom_fields(headers, log, dry_run)
    results["custom_fields"] = f"{sum(1 for r in field_results if r['status'] in ('created', 'exists'))}/{len(field_results)} OK"
    rate_pause(1.0)

    # Step 3: Custom Values
    cv_results = create_custom_values(headers, log, business_name, owner_phone, booking_link, dry_run)
    results["custom_values"] = f"{sum(1 for r in cv_results if r['status'] != 'failed')}/{len(cv_results)} OK"
    rate_pause(1.0)

    # Step 4: Tags
    tag_results = create_tags(headers, log, dry_run)
    results["tags"] = f"{sum(1 for r in tag_results if r['status'] in ('created', 'exists'))}/{len(tag_results)} OK"
    rate_pause(1.0)

    # Step 5: Workflow audit
    workflows = list_workflows(headers, log, dry_run)
    results["workflows_found"] = len(workflows) if not dry_run else "N/A (dry run)"

    # Step 6: Conversation AI documentation
    assess_conversation_ai(log)
    results["conversation_ai"] = "Spec documented (manual config required)"

    # Step 7: Workflow configuration documentation
    document_workflow_config(log)
    results["workflow_config"] = "Spec documented (manual build required)"

    # Summary
    log.add_summary(results)
    log.write()

    # Final output
    print("\n" + "=" * 60)
    print("  BUILD COMPLETE")
    print("=" * 60)
    for k, v in results.items():
        print(f"  {k:25s}: {v}")
    print("=" * 60)
    print(f"\n  Full log: {BUILD_LOG_PATH}")
    print()

    return results


# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def main():
    parser = argparse.ArgumentParser(
        description="MCTB v2 — Deploy Missed Call Text Back Chatbot to GHL SA-008",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Using env var:
  export GHL_SUB_ACCOUNT_KEY="pit-xxxxx"
  python3 mctb_v2_deploy.py

  # Explicit key:
  python3 mctb_v2_deploy.py --api-key "pit-xxxxx"

  # Dry run (no API calls):
  python3 mctb_v2_deploy.py --dry-run

  # With business details:
  python3 mctb_v2_deploy.py --api-key "pit-xxxxx" \\
    --business-name "Precision Plumbing" \\
    --owner-phone "+61412345678" \\
    --booking-link "https://book.precisionplumbing.com.au"
        """,
    )
    parser.add_argument(
        "--api-key",
        default=os.environ.get("GHL_SUB_ACCOUNT_KEY", ""),
        help="GHL sub-account API key for SA-008 (or set GHL_SUB_ACCOUNT_KEY env var)",
    )
    parser.add_argument("--business-name", default="Your Business", help="Business trading name")
    parser.add_argument("--owner-phone", default="", help="Owner phone (E.164 format)")
    parser.add_argument("--booking-link", default="", help="Online booking URL")
    parser.add_argument("--dry-run", action="store_true", help="Print API calls without executing")

    args = parser.parse_args()

    if not args.api_key and not args.dry_run:
        print("[ERROR] No API key provided.")
        print("  Set GHL_SUB_ACCOUNT_KEY env var or use --api-key flag.")
        print("  Or use --dry-run to see what would be created.")
        sys.exit(1)

    deploy(
        api_key=args.api_key or "DRY_RUN_KEY",
        business_name=args.business_name,
        owner_phone=args.owner_phone,
        booking_link=args.booking_link,
        dry_run=args.dry_run,
    )


if __name__ == "__main__":
    main()
