import { getAppUrl, isPubliclyReachableAppUrl } from "@/lib/env";
import { getThreadsConfig, getThreadsGraphBase } from "@/lib/social/threads-oauth";
import { resolvePublishableImageUrl } from "@/lib/social/publish-image";

export interface ThreadsPublishInput {
  accessToken: string;
  threadsUserId: string;
  caption: string;
  imageUrl?: string | null;
}

export interface ThreadsPublishResult {
  ok: boolean;
  postId?: string;
  permalink?: string;
  error?: string;
  skippedImage?: boolean;
}

async function createThreadsContainer(input: {
  userId: string;
  accessToken: string;
  text: string;
  imageUrl?: string | null;
}): Promise<{ id: string } | { error: string }> {
  const base = getThreadsGraphBase();
  const body = new URLSearchParams({
    media_type: input.imageUrl ? "IMAGE" : "TEXT",
    text: input.text.slice(0, 500),
    access_token: input.accessToken,
  });
  if (input.imageUrl) body.set("image_url", input.imageUrl);

  const res = await fetch(`${base}/${input.userId}/threads`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: body.toString(),
  });
  const data = (await res.json()) as { id?: string; error?: { message?: string } };
  if (!res.ok || !data.id) {
    return { error: data.error?.message || "Threads container create failed" };
  }
  return { id: data.id };
}

async function publishThreadsContainer(input: {
  userId: string;
  accessToken: string;
  creationId: string;
}): Promise<{ id: string } | { error: string }> {
  const base = getThreadsGraphBase();
  const body = new URLSearchParams({
    creation_id: input.creationId,
    access_token: input.accessToken,
  });
  const res = await fetch(`${base}/${input.userId}/threads_publish`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: body.toString(),
  });
  const data = (await res.json()) as { id?: string; error?: { message?: string } };
  if (!res.ok || !data.id) {
    return { error: data.error?.message || "Threads publish failed" };
  }
  return { id: data.id };
}

export async function publishToThreads(
  input: ThreadsPublishInput,
): Promise<ThreadsPublishResult> {
  const { appId } = getThreadsConfig();
  if (!appId) {
    return { ok: false, error: "Threads is not configured" };
  }
  if (!input.accessToken || !input.threadsUserId) {
    return { ok: false, error: "Threads account is not connected" };
  }

  const caption = input.caption?.trim() || "";
  if (!caption && !input.imageUrl) {
    return { ok: false, error: "Threads requires caption or image" };
  }

  let imageUrl = input.imageUrl ?? null;
  let skippedImage = false;
  const appOrigin = getAppUrl();
  if (imageUrl) {
    const resolved = await resolvePublishableImageUrl(imageUrl, appOrigin);
    if (
      !resolved ||
      (!isPubliclyReachableAppUrl(appOrigin) &&
        /localhost|127\.0\.0\.1/.test(resolved))
    ) {
      skippedImage = true;
      imageUrl = null;
      if (!caption) {
        return {
          ok: false,
          error:
            "Threads image publish needs a public HTTPS image URL (not localhost).",
        };
      }
    } else {
      imageUrl = resolved.startsWith("http")
        ? resolved
        : `${appOrigin.replace(/\/$/, "")}${resolved.startsWith("/") ? "" : "/"}${resolved}`;
    }
  }

  const container = await createThreadsContainer({
    userId: input.threadsUserId,
    accessToken: input.accessToken,
    text: caption,
    imageUrl,
  });
  if ("error" in container) {
    return { ok: false, error: container.error, skippedImage };
  }

  const published = await publishThreadsContainer({
    userId: input.threadsUserId,
    accessToken: input.accessToken,
    creationId: container.id,
  });
  if ("error" in published) {
    return { ok: false, error: published.error, skippedImage };
  }

  return {
    ok: true,
    postId: published.id,
    skippedImage,
  };
}
