/**
 * CW Endpoint Validator
 *
 * Validates that all ConnectWise API endpoints used by the application
 * are reachable and respond correctly. Uses the same axios instance
 * and credentials as the running app.
 *
 * Usage: bun ./utils/validateCwEndpoints.ts
 */

import { connectWiseApi } from "../src/constants";
import { prisma } from "../src/constants";

interface EndpointTest {
  name: string;
  method: "get" | "post" | "patch" | "delete";
  url: string;
  /** If true, a 404 is treated as "endpoint exists but resource doesn't" — still a pass. */
  allow404?: boolean;
}

// ---------------------------------------------------------------------------
// Build test list — some require real IDs from the database
// ---------------------------------------------------------------------------

async function buildTestList(): Promise<EndpointTest[]> {
  // Grab a sample opportunity from the DB to test with real IDs
  const sampleOpp = await prisma.opportunity.findFirst({
    where: { closedFlag: false },
    select: { cwOpportunityId: true, companyId: true },
    orderBy: { cwLastUpdated: "desc" },
  });

  const sampleCompany = await prisma.company.findFirst({
    select: { cw_CompanyId: true },
  });

  const oppId = sampleOpp?.cwOpportunityId ?? 1;
  const companyId = sampleCompany?.cw_CompanyId ?? 1;

  return [
    // ── Core counts (lightweight, always work) ──────────────────────────
    {
      name: "Opportunities count",
      method: "get",
      url: "/sales/opportunities/count",
    },
    {
      name: "Activities count",
      method: "get",
      url: "/sales/activities/count",
    },
    {
      name: "Companies count",
      method: "get",
      url: "/company/companies/count",
    },
    {
      name: "Members count",
      method: "get",
      url: "/system/members/count",
    },
    {
      name: "Catalog count",
      method: "get",
      url: "/procurement/catalog/count",
    },

    // ── Paginated list endpoints ────────────────────────────────────────
    {
      name: "Opportunities list (page 1, size 1)",
      method: "get",
      url: "/sales/opportunities?page=1&pageSize=1",
    },
    {
      name: "Activities list (page 1, size 1)",
      method: "get",
      url: "/sales/activities?page=1&pageSize=1",
    },
    {
      name: "Companies list (page 1, size 1)",
      method: "get",
      url: "/company/companies?page=1&pageSize=1",
    },
    {
      name: "Members list (page 1, size 1)",
      method: "get",
      url: "/system/members?page=1&pageSize=1",
    },
    {
      name: "Catalog list (page 1, size 1)",
      method: "get",
      url: "/procurement/catalog?page=1&pageSize=1",
    },
    {
      name: "User-defined fields (page 1)",
      method: "get",
      url: "/system/userDefinedFields?pageSize=1",
    },

    // ── Single-resource fetches (need real IDs) ─────────────────────────
    {
      name: `Opportunity #${oppId}`,
      method: "get",
      url: `/sales/opportunities/${oppId}`,
      allow404: true,
    },
    {
      name: `Opportunity #${oppId} forecast`,
      method: "get",
      url: `/sales/opportunities/${oppId}/forecast`,
      allow404: true,
    },
    {
      name: `Opportunity #${oppId} notes`,
      method: "get",
      url: `/sales/opportunities/${oppId}/notes`,
      allow404: true,
    },
    {
      name: `Opportunity #${oppId} contacts`,
      method: "get",
      url: `/sales/opportunities/${oppId}/contacts`,
      allow404: true,
    },
    {
      name: `Activities for opp #${oppId}`,
      method: "get",
      url: `/sales/activities/count?conditions=${encodeURIComponent(`opportunity/id=${oppId}`)}`,
      allow404: true,
    },
    {
      name: `Procurement products for opp #${oppId}`,
      method: "get",
      url: `/procurement/products?conditions=${encodeURIComponent(`opportunity/id=${oppId}`)}&fields=id,forecastDetailId,cancelledFlag`,
      allow404: true,
    },
    {
      name: `Company #${companyId}`,
      method: "get",
      url: `/company/companies/${companyId}`,
      allow404: true,
    },
    {
      name: `Company #${companyId} sites`,
      method: "get",
      url: `/company/companies/${companyId}/sites?pageSize=1`,
      allow404: true,
    },
    {
      name: `Company #${companyId} configurations`,
      method: "get",
      url: `/company/configurations?conditions=${encodeURIComponent(`company/id=${companyId}`)}&pageSize=1`,
      allow404: true,
    },
  ];
}

// ---------------------------------------------------------------------------
// Runner
// ---------------------------------------------------------------------------

async function main() {
  console.log(
    "╔══════════════════════════════════════════════════════════════╗",
  );
  console.log(
    "║          ConnectWise API Endpoint Validator                 ║",
  );
  console.log(
    "╚══════════════════════════════════════════════════════════════╝",
  );
  console.log();
  console.log(`Base URL: ${connectWiseApi.defaults.baseURL}`);
  console.log(`Timeout:  ${connectWiseApi.defaults.timeout ?? "none"}ms`);
  console.log();

  const tests = await buildTestList();
  let passed = 0;
  let failed = 0;
  let warned = 0;

  for (const test of tests) {
    const start = performance.now();
    try {
      const response = await connectWiseApi.request({
        method: test.method,
        url: test.url,
        timeout: 30_000, // Use a generous timeout for validation
      });
      const elapsed = Math.round(performance.now() - start);
      const statusTag =
        elapsed > 5000 ? `⚠️  SLOW (${elapsed}ms)` : `${elapsed}ms`;
      console.log(`  ✅  ${test.name} — ${response.status} [${statusTag}]`);
      if (elapsed > 5000) warned++;
      passed++;
    } catch (err: any) {
      const elapsed = Math.round(performance.now() - start);
      if (err?.isAxiosError) {
        const status = err.response?.status;
        const code = err.code;

        if (status === 404 && test.allow404) {
          console.log(
            `  ⚠️  ${test.name} — 404 (resource not found, endpoint OK) [${elapsed}ms]`,
          );
          warned++;
          continue;
        }

        if (code === "ECONNABORTED") {
          console.log(`  ❌  ${test.name} — TIMEOUT after ${elapsed}ms`);
        } else if (code === "ECONNREFUSED") {
          console.log(
            `  ❌  ${test.name} — CONNECTION REFUSED (CW server down?)`,
          );
        } else if (status) {
          console.log(
            `  ❌  ${test.name} — HTTP ${status} [${elapsed}ms]: ${err.response?.data?.message ?? err.message}`,
          );
        } else {
          console.log(
            `  ❌  ${test.name} — ${code ?? err.message} [${elapsed}ms]`,
          );
        }
      } else {
        console.log(`  ❌  ${test.name} — ${err.message} [${elapsed}ms]`);
      }
      failed++;
    }
  }

  console.log();
  console.log("─".repeat(64));
  console.log(
    `  Results: ${passed} passed, ${warned} warnings, ${failed} failed (${tests.length} total)`,
  );
  console.log("─".repeat(64));

  await prisma.$disconnect();
  process.exit(failed > 0 ? 1 : 0);
}

main().catch((err) => {
  console.error("Fatal error:", err.message);
  process.exit(1);
});
