/**
 * Agent-side social config scenario tests (no live Meta/LinkedIn API calls).
 *
 * Run: npx tsx scripts/test-social-config.ts
 */
import {
  getPlatformBlockReason,
  getPlatformIntegrationReport,
  isPlatformPublishEnabled,
  isSocialMediaGloballyEnabled,
  listPlatformIntegrationReports,
} from "../src/lib/social/config/social-config";
import {
  SOCIAL_PLATFORM_REGISTRY,
  platformSupportsContentType,
  platformSupportsDestination,
} from "../src/lib/social/config/platform-registry";
import {
  classifyProviderError,
  isRetryableErrorCode,
} from "../src/lib/social/publish-errors";
import { computeOverallPublishStatus } from "../src/lib/social/publish-result";
import {
  applyOutcomesToJob,
  createPublishJob,
  getPublishJob,
  savePublishJob,
} from "../src/lib/social/publish-jobs";
import { withPublishRetry } from "../src/lib/social/publish-retry";
import { getTokenLifecycleStatus } from "../src/lib/social/token-lifecycle";

type Case = { name: string; pass: boolean; detail?: string };

const results: Case[] = [];

function assert(name: string, pass: boolean, detail?: string) {
  results.push({ name, pass, detail });
  const mark = pass ? "PASS" : "FAIL";
  console.log(`${mark}  ${name}${detail ? ` — ${detail}` : ""}`);
}

function withEnv(patch: Record<string, string | undefined>, fn: () => void) {
  const keys = Object.keys(patch);
  const previous: Record<string, string | undefined> = {};
  for (const k of keys) {
    previous[k] = process.env[k];
    const v = patch[k];
    if (v === undefined) delete process.env[k];
    else process.env[k] = v;
  }
  try {
    fn();
  } finally {
    for (const k of keys) {
      const v = previous[k];
      if (v === undefined) delete process.env[k];
      else process.env[k] = v;
    }
  }
}

async function withEnvAsync(
  patch: Record<string, string | undefined>,
  fn: () => Promise<void>,
) {
  const keys = Object.keys(patch);
  const previous: Record<string, string | undefined> = {};
  for (const k of keys) {
    previous[k] = process.env[k];
    const v = patch[k];
    if (v === undefined) delete process.env[k];
    else process.env[k] = v;
  }
  try {
    await fn();
  } finally {
    for (const k of keys) {
      const v = previous[k];
      if (v === undefined) delete process.env[k];
      else process.env[k] = v;
    }
  }
}

async function main() {
  console.log("\n=== Social config scenario tests ===\n");

  withEnv(
    {
      SOCIAL_MEDIA_ENABLED: "true",
      FACEBOOK_ENABLED: "false",
      META_APP_ID: "test-app",
      META_APP_SECRET: "test-secret",
    },
    () => {
      const report = getPlatformIntegrationReport("facebook");
      assert("S1 Facebook disabled → status disabled", report.status === "disabled", report.status);
      assert("S1 Facebook disabled → no publish", !isPlatformPublishEnabled("facebook"));
      const block = getPlatformBlockReason("facebook");
      assert("S1 Facebook disabled → PLATFORM_DISABLED", block?.code === "PLATFORM_DISABLED", block?.code);
    },
  );

  withEnv(
    {
      SOCIAL_MEDIA_ENABLED: "true",
      FACEBOOK_ENABLED: "true",
      META_APP_ID: undefined,
      META_APP_SECRET: undefined,
      FACEBOOK_APP_ID: undefined,
      FACEBOOK_APP_SECRET: undefined,
      FACEBOOK_CLIENT_ID: undefined,
      FACEBOOK_CLIENT_SECRET: undefined,
    },
    () => {
      const report = getPlatformIntegrationReport("facebook");
      assert("S2 Facebook missing creds → missing_credentials", report.status === "missing_credentials", report.status);
      assert("S2 Facebook missing creds → publish blocked", !isPlatformPublishEnabled("facebook"));
      const block = getPlatformBlockReason("facebook");
      assert("S2 Facebook missing creds → MISSING_CREDENTIALS", block?.code === "MISSING_CREDENTIALS", block?.code);
    },
  );

  withEnv(
    {
      SOCIAL_MEDIA_ENABLED: "true",
      FACEBOOK_ENABLED: "true",
      INSTAGRAM_ENABLED: "true",
      LINKEDIN_ENABLED: "true",
      YOUTUBE_ENABLED: "true",
      META_APP_ID: "meta-id",
      META_APP_SECRET: "meta-secret",
      LINKEDIN_CLIENT_ID: "li-id",
      LINKEDIN_CLIENT_SECRET: "li-secret",
      GOOGLE_CLIENT_ID: "g-id",
      GOOGLE_CLIENT_SECRET: "g-secret",
    },
    () => {
      for (const p of ["facebook", "instagram", "linkedin", "youtube"] as const) {
        const report = getPlatformIntegrationReport(p);
        assert(`S3 ${p} → enabled`, report.status === "enabled", report.status);
        assert(`S3 ${p} → publish allowed`, isPlatformPublishEnabled(p));
        assert(`S3 ${p} → no block`, getPlatformBlockReason(p) === null);
        assert(`S3 ${p} → readiness ready`, report.readiness === "ready");
      }
    },
  );

  withEnv(
    {
      SOCIAL_MEDIA_ENABLED: "false",
      FACEBOOK_ENABLED: "true",
      META_APP_ID: "meta-id",
      META_APP_SECRET: "meta-secret",
    },
    () => {
      assert("S4 global off", !isSocialMediaGloballyEnabled());
      assert("S4 Facebook blocked when global off", !isPlatformPublishEnabled("facebook"));
    },
  );

  withEnv(
    {
      SOCIAL_MEDIA_ENABLED: "true",
      FACEBOOK_ENABLED: "true",
      LINKEDIN_ENABLED: "true",
      TWITTER_ENABLED: "true",
      META_APP_ID: "meta-id",
      META_APP_SECRET: "meta-secret",
      LINKEDIN_CLIENT_ID: "li-id",
      LINKEDIN_CLIENT_SECRET: "li-secret",
      TWITTER_CLIENT_ID: "tw-id",
      TWITTER_CLIENT_SECRET: "tw-secret",
    },
    () => {
      const fb = getPlatformIntegrationReport("facebook");
      assert(
        "S5 Facebook destinations = page only",
        fb.destinations.length === 1 && fb.destinations[0] === "page",
        fb.destinations.join(","),
      );
      const li = getPlatformIntegrationReport("linkedin");
      assert(
        "S5 LinkedIn destinations = profile (no org yet)",
        li.destinations.includes("profile") && !li.destinations.includes("organization"),
        li.destinations.join(","),
      );
      const tw = getPlatformIntegrationReport("twitter");
      assert(
        "S5 Twitter not implemented despite ENABLED+creds",
        tw.status === "not_implemented" && !isPlatformPublishEnabled("twitter"),
        tw.status,
      );
    },
  );

  withEnv(
    {
      SOCIAL_MEDIA_ENABLED: "true",
      FACEBOOK_ENABLED: "true",
      META_APP_ID: undefined,
      META_APP_SECRET: undefined,
      FACEBOOK_CLIENT_ID: "legacy-id",
      FACEBOOK_CLIENT_SECRET: "legacy-secret",
    },
    () => {
      const report = getPlatformIntegrationReport("facebook");
      assert("S6 FACEBOOK_CLIENT_* aliases work", report.status === "enabled", report.status);
    },
  );

  assert(
    "S7 registry facebook page + image",
    platformSupportsDestination("facebook", "page") && platformSupportsContentType("facebook", "image"),
  );
  assert(
    "S7 registry youtube video-only content",
    SOCIAL_PLATFORM_REGISTRY.youtube.contentTypes.includes("video") &&
      !SOCIAL_PLATFORM_REGISTRY.youtube.contentTypes.includes("text"),
  );
  assert("S7 twitter not implemented in registry", SOCIAL_PLATFORM_REGISTRY.twitter.implemented === false);
  assert("S7b threads implemented in registry", SOCIAL_PLATFORM_REGISTRY.threads.implemented === true);
  assert("S7c pinterest implemented in registry", SOCIAL_PLATFORM_REGISTRY.pinterest.implemented === true);
  assert("S7d tiktok implemented in registry", SOCIAL_PLATFORM_REGISTRY.tiktok.implemented === true);
  assert("S7e tiktok blocks IN by default", SOCIAL_PLATFORM_REGISTRY.tiktok.blockedCountries.includes("IN"));

  assert("S8 rate limit retryable", classifyProviderError("429 rate limit").code === "RATE_LIMITED");
  assert("S8 network retryable", isRetryableErrorCode("NETWORK_ERROR"));
  assert("S8 disabled not retryable", !isRetryableErrorCode("PLATFORM_DISABLED"));
  assert("S8 revoked not retryable", classifyProviderError("token revoked").retryable === false);

  assert(
    "S9 partial when mixed",
    computeOverallPublishStatus([
      { success: true },
      { success: false, error: "x" },
      { success: false, skipped: true, error: "skip" },
    ]) === "PARTIALLY_PUBLISHED",
  );
  assert(
    "S9 published when all success",
    computeOverallPublishStatus([{ success: true }, { success: true }]) === "PUBLISHED",
  );
  assert(
    "S9 failed when none succeed",
    computeOverallPublishStatus([{ success: false, error: "a" }]) === "FAILED",
  );

  assert(
    "S10 disconnected",
    getTokenLifecycleStatus({
      platform: "facebook",
      label: "Facebook",
      profileName: "",
      connected: false,
      connectionStatus: "disconnected",
    }) === "DISCONNECTED",
  );
  assert(
    "S10 expired by date",
    getTokenLifecycleStatus({
      platform: "facebook",
      label: "Facebook",
      profileName: "x",
      connected: true,
      connectionStatus: "connected",
      expiresAt: new Date(Date.now() - 60_000).toISOString(),
    }) === "EXPIRED",
  );
  assert(
    "S10 expiring soon",
    getTokenLifecycleStatus({
      platform: "linkedin",
      label: "LinkedIn",
      profileName: "x",
      connected: true,
      connectionStatus: "connected",
      expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
    }) === "EXPIRING_SOON",
  );

  const job = await createPublishJob({
    projectId: "proj_test",
    postId: "post_test",
    platforms: ["facebook", "linkedin"],
  });
  assert("S11 job queued", job.status === "QUEUED");
  const done = applyOutcomesToJob(job, [
    { platform: "facebook", success: true, permalink: "https://fb.example/1" },
    { platform: "linkedin", success: false, error: "fail", errorCode: "PROVIDER_ERROR" },
  ]);
  await savePublishJob(done);
  const loaded = await getPublishJob(job.id);
  assert("S11 job partial", loaded?.status === "PARTIALLY_PUBLISHED", loaded?.status);

  await withEnvAsync(
    {
      SOCIAL_PUBLISH_MAX_ATTEMPTS: "3",
      SOCIAL_PUBLISH_FAST_RETRY: "true",
    },
    async () => {
      let calls = 0;
      const result = await withPublishRetry({
        classify: () => ({ code: "NETWORK_ERROR", retryable: true }),
        run: async () => {
          calls += 1;
          if (calls < 3) return { success: false, error: "network blip" };
          return { success: true };
        },
      });
      assert("S12 retries then success", result.success && calls === 3, `calls=${calls}`);
    },
  );

  console.log("\n--- Integration report snapshot (current process env) ---\n");
  for (const p of listPlatformIntegrationReports()) {
    console.log(
      `${p.platform.padEnd(12)} ${p.status.padEnd(20)} creds=${String(p.credentialsConfigured).padEnd(5)} dest=${p.destinations.join("|") || "none"}`,
    );
  }

  const failed = results.filter((r) => !r.pass);
  console.log(`\n${results.length - failed.length}/${results.length} passed`);
  if (failed.length) {
    console.error("Failures:", failed.map((f) => f.name).join("; "));
    process.exit(1);
  }
  console.log("All social config scenarios passed.\n");
}

void main();
