import { createId, readDb, writeDb } from "@/lib/store";

const AUTH_URL = "https://www.pinterest.com/oauth/";
const TOKEN_URL = "https://api.pinterest.com/v5/oauth/token";

export const DEFAULT_PINTEREST_SCOPES = [
  "boards:read",
  "boards:write",
  "pins:read",
  "pins:write",
  "user_accounts:read",
];

export function pinterestOAuthConfigured() {
  return Boolean(process.env.PINTEREST_CLIENT_ID && process.env.PINTEREST_CLIENT_SECRET);
}

export function getPinterestOAuthConfig(origin?: string) {
  const clientId = process.env.PINTEREST_CLIENT_ID || "";
  const clientSecret = process.env.PINTEREST_CLIENT_SECRET || "";
  const redirectUri = process.env.PINTEREST_REDIRECT_URI || `${origin || "http://127.0.0.1:3000"}/api/auth/pinterest/callback`;
  return { clientId, clientSecret, redirectUri };
}

export async function createAuthorizationUrl(input: {
  origin?: string;
  scopes?: string[];
}) {
  const config = getPinterestOAuthConfig(input.origin);
  if (!config.clientId) {
    return { ok: false as const, error: "PINTEREST_CLIENT_ID is not configured" };
  }

  const state = createId("pstate");
  const scopes = input.scopes?.length ? input.scopes : DEFAULT_PINTEREST_SCOPES;
  const db = await readDb();
  db.oauth.state = {
    state,
    scopes,
    redirectUri: config.redirectUri,
    createdAt: new Date().toISOString(),
  };
  await writeDb(db);

  const url = new URL(AUTH_URL);
  url.searchParams.set("client_id", config.clientId);
  url.searchParams.set("redirect_uri", config.redirectUri);
  url.searchParams.set("response_type", "code");
  url.searchParams.set("scope", scopes.join(","));
  url.searchParams.set("state", state);
  return { ok: true as const, url: url.toString(), state, scopes, redirectUri: config.redirectUri };
}

export async function exchangeCodeForToken(input: {
  code: string;
  state: string;
  origin?: string;
}) {
  const db = await readDb();
  if (!db.oauth.state.state || db.oauth.state.state !== input.state) {
    return { ok: false as const, error: "OAuth state mismatch. Start the Pinterest OAuth flow again." };
  }

  const config = getPinterestOAuthConfig(input.origin);
  if (!config.clientId || !config.clientSecret) {
    return { ok: false as const, error: "PINTEREST_CLIENT_ID or PINTEREST_CLIENT_SECRET is not configured" };
  }

  const token = await requestToken(config.clientId, config.clientSecret, {
    grant_type: "authorization_code",
    code: input.code,
    redirect_uri: db.oauth.state.redirectUri || config.redirectUri,
  });
  if (!token.ok) return token;

  saveToken(db, token.data);
  db.oauth.state = { scopes: [] };
  await writeDb(db);
  return { ok: true as const, account: db.account, token: safeToken(db.oauth.token) };
}

export async function refreshPinterestToken() {
  const db = await readDb();
  const refreshToken = db.oauth.token.refreshToken;
  if (!refreshToken) return { ok: false as const, error: "No Pinterest refresh token saved" };

  const config = getPinterestOAuthConfig();
  if (!config.clientId || !config.clientSecret) {
    return { ok: false as const, error: "PINTEREST_CLIENT_ID or PINTEREST_CLIENT_SECRET is not configured" };
  }

  const token = await requestToken(config.clientId, config.clientSecret, {
    grant_type: "refresh_token",
    refresh_token: refreshToken,
  });
  if (!token.ok) return token;

  saveToken(db, {
    ...token.data,
    refresh_token: token.data.refresh_token || refreshToken,
  });
  await writeDb(db);
  return { ok: true as const, account: db.account, token: safeToken(db.oauth.token) };
}

export async function getSavedPinterestAccessToken() {
  const db = await readDb();
  const token = db.oauth.token.accessToken || process.env.PINTEREST_ACCESS_TOKEN || "";
  return token;
}

export async function getOAuthStatus() {
  const db = await readDb();
  const now = Date.now();
  const expiresAt = db.oauth.token.expiresAt ? new Date(db.oauth.token.expiresAt).getTime() : 0;
  const expired = Boolean(expiresAt && expiresAt <= now);
  return {
    configured: pinterestOAuthConfigured(),
    account: db.account,
    token: safeToken(db.oauth.token),
    pendingState: db.oauth.state.state ? {
      scopes: db.oauth.state.scopes,
      createdAt: db.oauth.state.createdAt,
      redirectUri: db.oauth.state.redirectUri,
    } : null,
    expired,
  };
}

async function requestToken(
  clientId: string,
  clientSecret: string,
  params: Record<string, string>,
) {
  const auth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
  const body = new URLSearchParams(params);
  const response = await fetch(TOKEN_URL, {
    method: "POST",
    headers: {
      authorization: `Basic ${auth}`,
      "content-type": "application/x-www-form-urlencoded",
      accept: "application/json",
    },
    body,
    cache: "no-store",
  });
  const data = await response.json().catch(() => null);
  if (!response.ok) {
    return {
      ok: false as const,
      status: response.status,
      error: data?.message || data?.error_description || data?.error || `Pinterest OAuth token request failed: ${response.status}`,
    };
  }
  return { ok: true as const, data: data as PinterestTokenResponse };
}

type PinterestTokenResponse = {
  access_token: string;
  refresh_token?: string;
  token_type?: string;
  scope?: string;
  expires_in?: number;
  refresh_token_expires_in?: number;
};

function saveToken(db: Awaited<ReturnType<typeof readDb>>, token: PinterestTokenResponse) {
  const now = Date.now();
  const scopes = parseScopes(token.scope || db.oauth.state.scopes.join(","));
  db.oauth.token = {
    accessToken: token.access_token,
    refreshToken: token.refresh_token || db.oauth.token.refreshToken,
    tokenType: token.token_type || "bearer",
    scope: token.scope || scopes.join(","),
    expiresAt: token.expires_in ? new Date(now + token.expires_in * 1000).toISOString() : undefined,
    refreshExpiresAt: token.refresh_token_expires_in ? new Date(now + token.refresh_token_expires_in * 1000).toISOString() : db.oauth.token.refreshExpiresAt,
    updatedAt: new Date(now).toISOString(),
  };
  db.account.tokenStatus = "valid";
  db.account.scopes = scopes;
  db.account.accountName = "Pinterest API connected";
  db.account.connectedAt = db.account.connectedAt || new Date(now).toISOString();
  db.account.expiresAt = db.oauth.token.expiresAt;
  db.account.updatedAt = new Date(now).toISOString();
}

function parseScopes(value: string) {
  return Array.from(new Set(String(value || "")
    .split(/[,\s]+/)
    .map((scope) => scope.trim())
    .filter(Boolean)));
}

function safeToken(token: { accessToken?: string; refreshToken?: string; expiresAt?: string; refreshExpiresAt?: string; scope?: string; updatedAt?: string }) {
  return {
    hasAccessToken: Boolean(token.accessToken),
    hasRefreshToken: Boolean(token.refreshToken),
    expiresAt: token.expiresAt,
    refreshExpiresAt: token.refreshExpiresAt,
    scope: token.scope,
    updatedAt: token.updatedAt,
  };
}
