#!/usr/bin/env node

/**
 * GitHub Webhook Testing Script
 *
 * This script allows testing of GitHub webhook endpoints locally.
 *
 * Usage:
 *   node test/webhooks/test-github-webhooks.js [event-type]
 *
 * Examples:
 *   node test/webhooks/test-github-webhooks.js                    # Test all events
 *   node test/webhooks/test-github-webhooks.js installation       # Test specific event
 *   node test/webhooks/test-github-webhooks.js pull_request       # Test pull request event
 */

import crypto from "crypto"
import http from "http"
import https from "https"
import { URL } from "url"
import { config } from "dotenv"
import path from "path"
import { fileURLToPath } from "url"
import fs from "fs"

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const rootDir = path.join(__dirname, "../..")

// Load environment variables in the same order as your server
// First try .env.local, then .env
const envLocalPath = path.join(rootDir, ".env.local")
const envPath = path.join(rootDir, ".env")

if (fs.existsSync(envLocalPath)) {
  console.log("Loading .env.local file...")
  config({ path: envLocalPath })
} else if (fs.existsSync(envPath)) {
  console.log("Loading .env file...")
  config({ path: envPath })
} else {
  console.log("No .env or .env.local file found")
}

// Configuration - now it will use the same secret as your server
const WEBHOOK_SECRET = process.env.GH_APP_WEBHOOK_SECRET || "dev-webhook-secret-2pjGGmaNy2gyEY4o3aU"
const SERVER_URL = process.env.SERVER_URL || "http://localhost:3001/cfapi/github/webhooks"

console.log(
  `Loaded webhook secret: ${WEBHOOK_SECRET.substring(0, 10)}... (length: ${WEBHOOK_SECRET.length})`,
)

// Color codes for terminal output
const colors = {
  reset: "\x1b[0m",
  bright: "\x1b[1m",
  red: "\x1b[31m",
  green: "\x1b[32m",
  yellow: "\x1b[33m",
  blue: "\x1b[34m",
  magenta: "\x1b[35m",
  cyan: "\x1b[36m",
}

// Test webhook payloads
const webhookPayloads = {
  ping: {
    zen: "Design for failure.",
    hook_id: 441537278,
    hook: {
      type: "App",
      id: 441537278,
      app_id: 413177,
    },
    sender: {
      login: "test-user",
      id: 123456,
      type: "User",
    },
  },

  installation: {
    action: "created",
    installation: {
      id: 64665617,
      account: {
        login: "test-user",
        id: 206515457,
        type: "User",
        site_admin: false,
      },
      repository_selection: "selected",
      access_tokens_url: "https://api.github.com/app/installations/64665617/access_tokens",
      repositories_url: "https://api.github.com/installation/repositories",
      app_id: 413177,
      app_slug: "codeflash-ai",
      target_id: 206515457,
      target_type: "User",
      permissions: {
        checks: "write",
        contents: "write",
        metadata: "read",
        pull_requests: "write",
        statuses: "write",
      },
      events: ["pull_request", "pull_request_review", "pull_request_review_comment"],
      created_at: "2025-04-16T05:33:42.000-07:00",
      updated_at: "2025-04-23T09:57:11.000-07:00",
    },
    sender: {
      login: "test-user",
      id: 206515457,
      type: "User",
    },
  },

  installation_repositories: {
    action: "added",
    installation: {
      id: 64665617,
      account: {
        login: "test-user",
        id: 206515457,
        type: "User",
      },
      repository_selection: "selected",
      app_id: 413177,
      app_slug: "codeflash-ai",
      target_id: 206515457,
      target_type: "User",
    },
    repository_selection: "selected",
    repositories_added: [
      {
        id: 971467577,
        node_id: "R_kgDOOedrOQ",
        name: "test-repo",
        full_name: "test-user/test-repo",
        private: false,
      },
    ],
    repositories_removed: [],
    sender: {
      login: "test-user",
      id: 206515457,
      type: "User",
    },
  },

  pull_request: {
    action: "opened",
    number: 42,
    pull_request: {
      id: 1234567890,
      number: 42,
      state: "open",
      locked: false,
      title: "Test Pull Request",
      user: {
        login: "test-user",
        id: 206515457,
        type: "User",
      },
      body: "This is a test pull request for webhook testing",
      created_at: "2025-05-30T10:00:00Z",
      updated_at: "2025-05-30T10:00:00Z",
      head: {
        label: "test-user:feature-branch",
        ref: "feature-branch",
        sha: "abc123def456",
      },
      base: {
        label: "test-user:main",
        ref: "main",
        sha: "def456abc123",
      },
      merged: false,
      mergeable: true,
      mergeable_state: "clean",
      merged_by: null,
      comments: 0,
      commits: 1,
      additions: 10,
      deletions: 5,
      changed_files: 2,
    },
    repository: {
      id: 971467577,
      name: "test-repo",
      full_name: "test-user/test-repo",
      owner: {
        login: "test-user",
        id: 206515457,
        type: "User",
      },
      private: false,
      description: "Test repository",
      fork: false,
      created_at: "2025-01-01T00:00:00Z",
      updated_at: "2025-05-30T10:00:00Z",
      pushed_at: "2025-05-30T10:00:00Z",
      default_branch: "main",
    },
    installation: {
      id: 64665617,
    },
    sender: {
      login: "test-user",
      id: 206515457,
      type: "User",
    },
  },

  pull_request_closed: {
    action: "closed",
    number: 42,
    pull_request: {
      id: 1234567890,
      number: 42,
      state: "closed",
      locked: false,
      title: "Test Pull Request",
      user: {
        login: "codeflash-ai[bot]",
        id: 148906541,
        type: "Bot",
      },
      merged: true,
      merged_by: {
        login: "test-user",
        id: 206515457,
        type: "User",
      },
      head: {
        ref: "codeflash-optimize-pr41-2025-05-30T10:00:00Z",
        sha: "abc123def456",
      },
      base: {
        ref: "main",
      },
    },
    repository: {
      id: 971467577,
      name: "test-repo",
      full_name: "test-user/test-repo",
      owner: {
        login: "test-user",
        id: 206515457,
      },
    },
    installation: {
      id: 64665617,
    },
    sender: {
      id: 206515457,
    },
  },

  pull_request_synchronize: {
    action: "synchronize",
    number: 42,
    pull_request: {
      id: 1234567890,
      number: 42,
      user: {
        login: "test-user",
        id: 206515457,
      },
      head: {
        ref: "feature-branch",
      },
    },
    repository: {
      name: "test-repo",
      full_name: "test-user/test-repo",
      owner: {
        login: "test-user",
      },
    },
    sender: {
      id: 206515457,
    },
  },

  marketplace_purchase: {
    action: "purchased",
    effective_date: "2025-05-30T00:00:00+00:00",
    marketplace_purchase: {
      account: {
        type: "User",
        id: 206515457,
        login: "test-user",
      },
      billing_cycle: "monthly",
      unit_count: 1,
      plan: {
        id: 12345,
        name: "Pro Plan",
        description: "Professional plan with advanced features",
        monthly_price_in_cents: 1999,
        yearly_price_in_cents: 19990,
        price_model: "per-unit",
        unit_name: "user",
      },
    },
    sender: {
      login: "test-user",
      id: 206515457,
      type: "User",
    },
  },

  check_suite: {
    action: "requested",
    check_suite: {
      id: 987654321,
      head_branch: "feature-branch",
      head_sha: "abc123def456",
      status: "queued",
      before: "def456abc123",
      after: "abc123def456",
      app: {
        id: 413177,
        slug: "codeflash-ai",
        name: "Codeflash AI",
      },
    },
    repository: {
      id: 971467577,
      name: "test-repo",
      full_name: "test-user/test-repo",
      owner: {
        login: "test-user",
        id: 206515457,
      },
    },
    sender: {
      login: "test-user",
      id: 206515457,
    },
  },
}

// Function to generate GitHub webhook signature
function generateSignature(payload, secret) {
  const hmac = crypto.createHmac("sha256", secret)
  hmac.update(JSON.stringify(payload))
  return `sha256=${hmac.digest("hex")}`
}

// Function to make HTTP request
function makeRequest(options, payload) {
  return new Promise((resolve, reject) => {
    const url = new URL(SERVER_URL)
    const client = url.protocol === "https:" ? https : http

    const req = client.request(
      {
        hostname: url.hostname,
        port: url.port || (url.protocol === "https:" ? 443 : 80),
        path: url.pathname,
        method: "POST",
        headers: options.headers,
      },
      res => {
        let data = ""
        res.on("data", chunk => (data += chunk))
        res.on("end", () => {
          resolve({
            statusCode: res.statusCode,
            headers: res.headers,
            body: data,
          })
        })
      },
    )

    req.on("error", reject)
    req.write(JSON.stringify(payload))
    req.end()
  })
}

// Function to send webhook
async function sendWebhook(eventType, payload) {
  const signature = generateSignature(payload, WEBHOOK_SECRET)
  const deliveryId = crypto.randomUUID()

  // Handle event names that include action (e.g., "pull_request_closed")
  let githubEventType = eventType
  if (eventType.includes("_") && !eventType.includes(".")) {
    // Check if this is a compound event like pull_request_closed
    const parts = eventType.split("_")
    if (parts[0] === "pull" && parts[1] === "request") {
      githubEventType = "pull_request"
      // Update the action in the payload if needed
      if (parts.length > 2) {
        payload.action = parts.slice(2).join("_")
      }
    }
  }

  console.log(
    `\n${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`,
  )
  console.log(`${colors.bright}Testing webhook: ${colors.yellow}${eventType}${colors.reset}`)
  console.log(
    `${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`,
  )
  console.log(`${colors.blue}Event Type:${colors.reset} ${githubEventType}`)
  console.log(`${colors.blue}Action:${colors.reset} ${payload.action || "N/A"}`)
  console.log(`${colors.blue}Delivery ID:${colors.reset} ${deliveryId}`)
  console.log(`${colors.blue}Signature:${colors.reset} ${signature.substring(0, 50)}...`)
  console.log(`${colors.blue}Payload size:${colors.reset} ${JSON.stringify(payload).length} bytes`)

  const headers = {
    "Content-Type": "application/json",
    "X-GitHub-Event": githubEventType,
    "X-GitHub-Delivery": deliveryId,
    "X-Hub-Signature-256": signature,
    "User-Agent": "GitHub-Hookshot/test",
  }

  try {
    const startTime = Date.now()
    const response = await makeRequest({ headers }, payload)
    const duration = Date.now() - startTime

    const statusColor =
      response.statusCode >= 200 && response.statusCode < 300 ? colors.green : colors.red
    console.log(`\n${colors.bright}Response:${colors.reset}`)
    console.log(
      `${colors.blue}Status:${colors.reset} ${statusColor}${response.statusCode}${colors.reset} (${duration}ms)`,
    )
    console.log(`${colors.blue}Body:${colors.reset} ${response.body || "(empty)"}`)

    if (response.statusCode >= 200 && response.statusCode < 300) {
      console.log(`${colors.green}✓ Webhook delivered successfully${colors.reset}`)
    } else {
      console.log(`${colors.red}✗ Webhook delivery failed${colors.reset}`)
    }
  } catch (error) {
    console.error(`${colors.red}✗ Error:${colors.reset}`, error.message)
    if (error.code === "ECONNREFUSED") {
      console.error(`${colors.yellow}Is your server running on ${SERVER_URL}?${colors.reset}`)
    }
  }
}

// Function to display usage
function displayUsage() {
  console.log(`
${colors.bright}GitHub Webhook Testing Script${colors.reset}

${colors.yellow}Usage:${colors.reset}
  node test/webhooks/test-github-webhooks.js [options] [event-type]

${colors.yellow}Options:${colors.reset}
  -h, --help     Show this help message
  -l, --list     List all available webhook events

${colors.yellow}Examples:${colors.reset}
  node test/webhooks/test-github-webhooks.js                      # Test all events
  node test/webhooks/test-github-webhooks.js installation         # Test installation event
  node test/webhooks/test-github-webhooks.js pull_request         # Test PR opened event

${colors.yellow}Available events:${colors.reset}
  ${Object.keys(webhookPayloads).join(", ")}

${colors.yellow}Environment variables:${colors.reset}
  SERVER_URL=${SERVER_URL}
  GH_APP_WEBHOOK_SECRET=${WEBHOOK_SECRET.substring(0, 10)}... (from .env.local)
`)
}

// Main function
async function main() {
  const args = process.argv.slice(2)

  if (args.includes("-h") || args.includes("--help")) {
    displayUsage()
    process.exit(0)
  }

  if (args.includes("-l") || args.includes("--list")) {
    console.log(`${colors.bright}Available webhook events:${colors.reset}`)
    Object.keys(webhookPayloads).forEach(event => {
      console.log(`  - ${event}`)
    })
    process.exit(0)
  }

  console.log(`${colors.bright}GitHub Webhook Local Testing${colors.reset}`)
  console.log(`${colors.blue}Server URL:${colors.reset} ${SERVER_URL}`)
  console.log(
    `${colors.blue}Webhook Secret:${colors.reset} ${WEBHOOK_SECRET.substring(0, 10)}... (matches server: ${WEBHOOK_SECRET.startsWith("PS$:3rM%*T") ? "✓" : "✗"})`,
  )

  const eventType = args[0]

  if (eventType) {
    // Test specific event
    if (!webhookPayloads[eventType]) {
      console.error(`${colors.red}Error: Unknown event type '${eventType}'${colors.reset}`)
      console.log(`Run with --list to see available events`)
      process.exit(1)
    }
    await sendWebhook(eventType, webhookPayloads[eventType])
  } else {
    // Test all events
    console.log(`\n${colors.yellow}Testing all webhook events...${colors.reset}`)
    for (const [event, payload] of Object.entries(webhookPayloads)) {
      await sendWebhook(event, payload)
      // Small delay between requests
      await new Promise(resolve => setTimeout(resolve, 500))
    }
  }

  console.log(`\n${colors.green}Testing complete!${colors.reset}`)
}

// Run the script
main().catch(error => {
  console.error(`${colors.red}Fatal error:${colors.reset}`, error)
  process.exit(1)
})
