const DEFAULT_HEADERS = {
  "Content-Type": "application/json"
};

const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000";
const PORTAL_SESSION_STORAGE_KEY = "powerup.prenotazioni.portal-session";
const PORTAL_SHARED_SESSION_STORAGE_KEY = "powerup.portal.session-token";
const PORTAL_SYNC_RETRY_WINDOW_MS = 15000;

let syncedPortalSessionToken: string | null = null;
let inflightPortalSync: Promise<void> | null = null;
let lastPortalSyncAttemptToken: string | null = null;
let lastPortalSyncAttemptAt = 0;

function resolveBrowserReachableBaseUrl(rawUrl: string): string {
  const trimmedUrl = rawUrl.trim();
  if (!trimmedUrl) {
    return trimmedUrl;
  }

  if (typeof window === "undefined") {
    return trimmedUrl.replace(/\/+$/, "");
  }

  try {
    const parsedUrl = new URL(trimmedUrl, window.location.origin);
    if (parsedUrl.hostname === "localhost" || parsedUrl.hostname === "127.0.0.1") {
      parsedUrl.protocol = window.location.protocol;
      parsedUrl.hostname = window.location.hostname;
    }
    return parsedUrl.toString().replace(/\/+$/, "");
  } catch {
    return trimmedUrl.replace(/\/+$/, "");
  }
}

function extractErrorDetail(rawText: string): string | null {
  if (!rawText) {
    return null;
  }

  try {
    const parsed = JSON.parse(rawText) as { detail?: unknown };
    const detail = parsed.detail;
    if (typeof detail === "string" && detail.trim()) {
      return detail.trim();
    }
    if (Array.isArray(detail)) {
      const firstMessage = detail
        .map((item) => {
          if (!item || typeof item !== "object" || !("msg" in item)) {
            return null;
          }
          const message = item.msg;
          if (typeof message !== "string" || !message.trim()) {
            return null;
          }
          return message.replace(/^Value error,\s*/i, "").trim();
        })
        .find((message): message is string => Boolean(message));
      if (firstMessage) {
        return firstMessage;
      }
    }
  } catch {
    // Fall through to raw text.
  }

  return rawText.trim() || null;
}

function getPortalSessionToken(): string | null {
  if (typeof window === "undefined") {
    return null;
  }

  try {
    const params = new URLSearchParams(window.location.search);
    const tokenFromUrl = params.get("session")?.trim();
    if (tokenFromUrl) {
      window.sessionStorage.setItem(PORTAL_SESSION_STORAGE_KEY, tokenFromUrl);
      return tokenFromUrl;
    }
  } catch {
    // Ignore malformed URL state and fall back to session storage.
  }

  const sharedPortalToken = window.localStorage.getItem(PORTAL_SHARED_SESSION_STORAGE_KEY)?.trim();
  if (sharedPortalToken) {
    const storedToken = window.sessionStorage.getItem(PORTAL_SESSION_STORAGE_KEY)?.trim();
    if (storedToken !== sharedPortalToken) {
      window.sessionStorage.setItem(PORTAL_SESSION_STORAGE_KEY, sharedPortalToken);
    }
    return sharedPortalToken;
  }

  const storedToken = window.sessionStorage.getItem(PORTAL_SESSION_STORAGE_KEY)?.trim();
  return storedToken || null;
}

function buildAuthorizedHeaders(initHeaders?: HeadersInit): Headers {
  const headers = new Headers(DEFAULT_HEADERS);
  const portalSessionToken = getPortalSessionToken();
  if (portalSessionToken) {
    headers.set("Authorization", `Bearer ${portalSessionToken}`);
  }

  if (initHeaders) {
    new Headers(initHeaders).forEach((value, key) => {
      headers.set(key, value);
    });
  }

  return headers;
}

async function ensurePortalContextSynced(): Promise<void> {
  if (typeof window === "undefined") {
    return;
  }

  const sessionToken = getPortalSessionToken();
  if (!sessionToken || syncedPortalSessionToken === sessionToken) {
    return;
  }

  if (
    lastPortalSyncAttemptToken === sessionToken &&
    Date.now() - lastPortalSyncAttemptAt < PORTAL_SYNC_RETRY_WINDOW_MS
  ) {
    return;
  }

  if (inflightPortalSync) {
    return inflightPortalSync;
  }

  inflightPortalSync = fetch(`${resolveBrowserReachableBaseUrl(API_BASE_URL)}/portal-context/sync`, {
    method: "POST",
    headers: DEFAULT_HEADERS,
    body: JSON.stringify({ session_token: sessionToken }),
    cache: "no-store"
  })
    .then(async (response) => {
      lastPortalSyncAttemptToken = sessionToken;
      lastPortalSyncAttemptAt = Date.now();
      if (!response.ok) {
        const detail = await response.text();
        throw new Error(detail || `Sync failed with status ${response.status}`);
      }
      syncedPortalSessionToken = sessionToken;
    })
    .catch((error) => {
      console.warn("Sincronizzazione tenant prenotazioni non riuscita", error);
    })
    .finally(() => {
      inflightPortalSync = null;
    });

  return inflightPortalSync;
}

export async function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {
  if (path !== "/portal-context/sync") {
    await ensurePortalContextSynced();
  }

  const response = await fetch(`${resolveBrowserReachableBaseUrl(API_BASE_URL)}${path}`, {
    ...init,
    headers: buildAuthorizedHeaders(init?.headers),
    cache: "no-store"
  });

  if (!response.ok) {
    const text = await response.text();
    const detail = extractErrorDetail(text);
    throw new Error(detail || `Request failed with status ${response.status}`);
  }

  return response.json() as Promise<T>;
}

export function todayString(): string {
  const now = new Date();
  const offset = now.getTimezoneOffset();
  const local = new Date(now.getTime() - offset * 60_000);
  return local.toISOString().slice(0, 10);
}
