import { NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { getOrCreateSettingsForUser } from "@/lib/user-settings";
import { getActiveAccountId } from "@/lib/account-context";
import { assertAccountOwnedByUser } from "@/lib/auth/accounts";
import { getSessionUser } from "@/lib/auth/session";
import {
  exchangeCodeForToken,
  exchangeForLongLivedToken,
  fetchThreadsProfile,
  getAppBaseUrl,
  getThreadsAppId,
  getThreadsAppSecret,
  saveThreadsAuthForAccount,
} from "@/lib/threads-api";

export async function GET(request: Request) {
  let homeUrl: URL;
  try {
    homeUrl = new URL("/matrix", new URL(request.url).origin);
  } catch {
    return NextResponse.json({ error: "invalid request url" }, { status: 400 });
  }

  try {
    const sessionUser = await getSessionUser();
    const settings = sessionUser ? await getOrCreateSettingsForUser(sessionUser.id) : null;
    homeUrl = new URL("/matrix", getAppBaseUrl(request, settings?.appUrl));
    const { searchParams } = new URL(request.url);
    const error = searchParams.get("error");
    const code = searchParams.get("code");
    const state = searchParams.get("state");

    if (error) {
      homeUrl.searchParams.set("threads_error", error);
      return NextResponse.redirect(homeUrl);
    }

    if (!code) {
      homeUrl.searchParams.set("threads_error", "missing_code");
      return NextResponse.redirect(homeUrl);
    }

    if (!sessionUser || !settings) {
      homeUrl.searchParams.set("threads_error", "請先登入後再綁定 Threads");
      return NextResponse.redirect(homeUrl);
    }

    const appId = getThreadsAppId();
    const appSecret = getThreadsAppSecret();

    if (!appId || !appSecret) {
      homeUrl.searchParams.set("threads_error", "missing_app_credentials");
      return NextResponse.redirect(homeUrl);
    }

    const stateAccountId = state && state !== "threadtools" ? state : null;
    const accountId = stateAccountId ?? (await getActiveAccountId());
    if (!accountId) {
      homeUrl.searchParams.set("threads_error", "no_active_account");
      return NextResponse.redirect(homeUrl);
    }

    let accountExists;
    try {
      accountExists = await assertAccountOwnedByUser(sessionUser.id, accountId);
    } catch {
      homeUrl.searchParams.set("threads_error", "account_not_found");
      return NextResponse.redirect(homeUrl);
    }

    const redirectUri = `${getAppBaseUrl(request, settings.appUrl)}/api/threads/oauth/callback`;
    const shortLived = await exchangeCodeForToken({
      appId,
      appSecret,
      code,
      redirectUri,
    });

    const longLived = await exchangeForLongLivedToken(appSecret, shortLived.accessToken);

    await saveThreadsAuthForAccount(accountId, {
      accessToken: longLived.accessToken,
      userId: shortLived.userId,
      expiresIn: longLived.expiresIn,
    });

    const profile = await fetchThreadsProfile(longLived.accessToken);
    if (profile.username) {
      const isPlaceholderName =
        !accountExists.displayName ||
        accountExists.displayName === "待綁定帳號" ||
        accountExists.displayName === "新經營帳號";
      await prisma.account.update({
        where: { id: accountId },
        data: {
          username: profile.username,
          valid: true,
          ...(isPlaceholderName ? { displayName: `@${profile.username}` } : {}),
        },
      });
    }

    await prisma.setting.update({
      where: { userId: sessionUser.id },
      data: { publishViaApi: true },
    });

    homeUrl.searchParams.set("threads_connected", "1");
    return NextResponse.redirect(homeUrl);
  } catch (err) {
    const message = err instanceof Error ? err.message : "oauth_failed";
    homeUrl.searchParams.set("threads_error", message);
    return NextResponse.redirect(homeUrl);
  }
}
