import { promises as fs } from "fs";
import { getAppUrl } from "@/lib/env";
import { resolveLocalMediaPath } from "@/lib/storage/media-files";

export function getTikTokRedirectUri() {
  return (
    process.env.TIKTOK_REDIRECT_URI ??
    process.env.TIKTOK_SOCIAL_REDIRECT_URI ??
    `${getAppUrl()}/connected-accounts/oauth/tiktok/callback`
  );
}

export function getTikTokConfig() {
  return {
    clientKey:
      process.env.TIKTOK_CLIENT_KEY?.trim() ||
      process.env.TIKTOK_CLIENT_ID?.trim() ||
      "",
    clientSecret: process.env.TIKTOK_CLIENT_SECRET?.trim() || "",
    redirectUri: getTikTokRedirectUri(),
    scopes: (
      process.env.TIKTOK_SCOPES?.trim() ||
      "user.info.basic,video.upload,video.publish"
    )
      .split(/[,\s]+/)
      .filter(Boolean),
  };
}

export function buildTikTokAuthUrl(state: string): string {
  const { clientKey, redirectUri, scopes } = getTikTokConfig();
  if (!clientKey) throw new Error("TikTok OAuth is not configured");
  const params = new URLSearchParams({
    client_key: clientKey,
    response_type: "code",
    scope: scopes.join(","),
    redirect_uri: redirectUri,
    state,
  });
  return `https://www.tiktok.com/v2/auth/authorize/?${params.toString()}`;
}

export async function exchangeTikTokCode(code: string): Promise<{
  accessToken: string;
  refreshToken?: string;
  expiresIn?: number;
  openId: string;
}> {
  const { clientKey, clientSecret, redirectUri } = getTikTokConfig();
  const res = await fetch("https://open.tiktokapis.com/v2/oauth/token/", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      client_key: clientKey,
      client_secret: clientSecret,
      code,
      grant_type: "authorization_code",
      redirect_uri: redirectUri,
    }).toString(),
  });
  const data = (await res.json()) as {
    access_token?: string;
    refresh_token?: string;
    expires_in?: number;
    open_id?: string;
    error?: string;
    error_description?: string;
  };
  if (!res.ok || !data.access_token || !data.open_id) {
    throw new Error(
      data.error_description || data.error || "TikTok token exchange failed",
    );
  }
  return {
    accessToken: data.access_token,
    refreshToken: data.refresh_token,
    expiresIn: data.expires_in,
    openId: data.open_id,
  };
}

export async function fetchTikTokUser(accessToken: string): Promise<{
  displayName: string;
  openId: string;
}> {
  const res = await fetch(
    "https://open.tiktokapis.com/v2/user/info/?fields=open_id,display_name,avatar_url",
    {
      headers: { Authorization: `Bearer ${accessToken}` },
    },
  );
  const data = (await res.json()) as {
    data?: { user?: { open_id?: string; display_name?: string } };
    error?: { message?: string };
  };
  const user = data.data?.user;
  if (!res.ok || !user?.open_id) {
    throw new Error(data.error?.message || "Failed to load TikTok user");
  }
  return {
    openId: user.open_id,
    displayName: user.display_name || "TikTok user",
  };
}

async function initTikTokUpload(accessToken: string, videoSize: number): Promise<{
  publishId: string;
  uploadUrl: string;
} | { error: string }> {
  const res = await fetch(
    "https://open.tiktokapis.com/v2/post/publish/inbox/video/init/",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json; charset=UTF-8",
      },
      body: JSON.stringify({
        source_info: {
          source: "FILE_UPLOAD",
          video_size: videoSize,
          chunk_size: videoSize,
          total_chunk_count: 1,
        },
      }),
    },
  );
  const data = (await res.json()) as {
    data?: { publish_id?: string; upload_url?: string };
    error?: { code?: string; message?: string };
  };
  if (!res.ok || !data.data?.publish_id || !data.data.upload_url) {
    return {
      error:
        data.error?.message ||
        "TikTok upload init failed — ensure Content Posting API access is approved",
    };
  }
  return { publishId: data.data.publish_id, uploadUrl: data.data.upload_url };
}

export async function publishToTikTok(input: {
  accessToken: string;
  caption: string;
  videoUrl: string | null;
}): Promise<{ ok: boolean; publishId?: string; error?: string }> {
  const { clientKey } = getTikTokConfig();
  if (!clientKey) return { ok: false, error: "TikTok is not configured" };
  if (!input.accessToken) return { ok: false, error: "TikTok account is not connected" };
  if (!input.videoUrl) return { ok: false, error: "TikTok requires a video file" };

  const localPath = resolveLocalMediaPath(input.videoUrl);
  if (!localPath) {
    return {
      ok: false,
      error: "TikTok publish requires a local MP4 under /api/media/…",
    };
  }

  let buffer: Buffer;
  try {
    buffer = await fs.readFile(localPath);
  } catch {
    return { ok: false, error: `Video file not found: ${localPath}` };
  }

  const init = await initTikTokUpload(input.accessToken, buffer.length);
  if ("error" in init) return { ok: false, error: init.error };

  const uploadRes = await fetch(init.uploadUrl, {
    method: "PUT",
    headers: {
      "Content-Type": "video/mp4",
      "Content-Length": String(buffer.length),
      "Content-Range": `bytes 0-${buffer.length - 1}/${buffer.length}`,
    },
    body: new Uint8Array(buffer),
  });
  if (!uploadRes.ok) {
    const text = await uploadRes.text().catch(() => "");
    return {
      ok: false,
      error: `TikTok video upload failed (${uploadRes.status}): ${text.slice(0, 200)}`,
    };
  }

  // Inbox upload — creator finishes in TikTok app (API limitation for many apps).
  // Direct publish endpoint requires additional audit approval.
  return {
    ok: true,
    publishId: init.publishId,
  };
}
