import createClient from "openapi-fetch";
import { useMemo } from "react";
import { useToken } from "../app/components/TokenProvider";
// import { toast } from '@/app/(root)/chakraProviders';

import { paths } from "./gen";

let sunoSessionId: string | null = null;
let sunoSessionIdTTL: number = new Date().getTime();
async function getBrowserToken() {
  try {
    const browserData = { timestamp: new Date().getTime() };
    // Making this semi-structured so we can pass some sealed client intel
    // in a future PR.
    return JSON.stringify({ token: btoa(JSON.stringify(browserData)) });
  } catch (e) {
    return JSON.stringify({ token: "error" });
  }
}

export function getSunoSessionId() {
  const currentTimestamp = new Date().getTime();
  if (currentTimestamp >= sunoSessionIdTTL!) return null;
  return sunoSessionId;
}

function updateSunoSessionId(res: Response) {
  const currentTimestamp = new Date().getTime();
  const newSessionId = res.headers.get("Session-Id");
  if (newSessionId) {
    if (newSessionId != sunoSessionId) {
      sunoSessionId = newSessionId;
      sunoSessionIdTTL = currentTimestamp + 15 * 60 * 1000;
    } else if (currentTimestamp >= sunoSessionIdTTL!) {
      sunoSessionId = newSessionId;
      sunoSessionIdTTL = currentTimestamp + 15 * 60 * 1000;
    }
  }
}

export function clearSunoSessionId() {
  sunoSessionId = null;
  sunoSessionIdTTL = new Date().getTime();
}

export function useApiClient() {
  const apiBase = process.env.NEXT_PUBLIC_API_BASE_ECS;
  const deviceId = null;
  const { token } = useToken();
  return useMemo(
    () =>
      createClient<paths>({
        baseUrl: apiBase || "/",
        fetch: async (url: any, options?: RequestInit) => {
          // Not that we should be fetching with the API client in SSR, but
          // `useAuth()` does not expose `getToken` in SSR
          const browserToken = await getBrowserToken();
          const mergedHeaders = Object.assign(
            {},
            options?.headers || {},
            token ? { Authorization: `Bearer ${token}` } : {},
            deviceId ? { "Device-Id": deviceId } : {},
            browserToken ? { "Browser-Token": browserToken } : {}
          );
          return fetch(url, {
            ...options,
            headers: mergedHeaders,
          }).then((res) => {
            if (
              res.status === 429 &&
              res.url.endsWith("/update_reaction_type/")
            ) {
              // toast({
              //   title:
              //     'Rate limit exceeded. Please wait before retrying actions.',
              //   status: 'error',
              //   duration: 2000,
              //   isClosable: true,
              // });
            }
            updateSunoSessionId(res);
            return res;
          });
        },
      }),
    [apiBase, token]
  );
}

export const createTestApiClient = () => {
  const apiBase = process.env.NEXT_PUBLIC_API_BASE_ECS;
  return createClient<paths>({
    baseUrl: apiBase || "/",
    fetch: async (url: any, options?: RequestInit) => {
      return fetch(url, {
        ...options,
        headers: {
          ...options?.headers,
          Authorization: `Bearer TEST-TOKEN`,
        },
      });
    },
  });
};

export type ApiClient = ReturnType<typeof useApiClient>;

// Helper function to fetch profile data with proper authentication
export async function fetchProfile(creatorName: string) {
  // This function still uses the env token for now, but can be updated to accept a token param if needed
  const token = process.env.NEXT_PUBLIC_SUNO_API_KEY;
  const browserToken = await getBrowserToken();

  const url = `https://studio-api.prod.suno.com/api/profiles/${creatorName}?page=1&playlists_sort_by=upvote_count&clips_sort_by=upvote_count`;

  const response = await fetch(url, {
    headers: {
      Authorization: `Bearer ${token}`,
      "Browser-Token": browserToken,
      "Content-Type": "application/json",
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch profile: ${response.status}`);
  }

  return response.json();
}
