export type CapsearchSession = {
  user: {
    id: number;
    email: string | null;
    name: string | null;
    initials: string;
  };
  client: {
    id: number;
    name: string | null;
    isCapsearch: boolean;
    isGuest: boolean;
    isFinancier: boolean;
  };
  organization: {
    id: number | null;
    name: string | null;
    ident: string | null;
  };
};

/**
 * Auth sequence overview
 *
 * Browser on Next.js
 *   -> GET /api/auth/me
 *      <- 200 (already has JWT cookies) OR 401
 *
 * If 401:
 *   -> POST /api/auth/session-token (includes Symfony PHP session cookie)
 *      <- 200 + Set-Cookie(access, refresh) OR 401 (no active Symfony session)
 *   -> GET /api/auth/me
 *      <- 200 user/client/org
 *
 * During API usage:
 *   -> GET /api/...
 *      <- 200 OR 401 (expired access token)
 *   -> POST /api/auth/refresh
 *      <- 200 + rotated cookies OR 401
 *   -> retry GET /api/...
 */
export type AuthDiagnostics = {
  meBefore: number | "network_error";
  sessionToken: number | "network_error";
  meAfterSessionToken: number | "network_error";
  refresh: number | "network_error";
  meAfterRefresh: number | "network_error";
};

export type AuthDebugStep = {
  path: string;
  method: "GET" | "POST";
  status: number | "network_error";
  ok: boolean;
  bodySnippet: string;
};

export type AuthDebugTrace = {
  startedAt: string;
  finishedAt: string;
  steps: AuthDebugStep[];
};

export const capsearchBaseUrl =
  process.env.NEXT_PUBLIC_CAPSEARCH_API_BASE_URL ??
  "https://frans.s.capsearch.com/index.php";

export const legacyUrl = (path: string) => `${capsearchBaseUrl}/${path}`;

const apiUrl = (path: string) => `${capsearchBaseUrl}${path}`;

/**
 * GET /api/auth/me ("who am i")
 *
 * Example 200 response:
 * {
 *   "user": {
 *     "id": 42,
 *     "email": "john@example.com",
 *     "name": "John Doe",
 *     "initials": "JD"
 *   },
 *   "client": {
 *     "id": 7,
 *     "name": "John - Capsearch",
 *     "isCapsearch": true,
 *     "isGuest": false,
 *     "isFinancier": false
 *   },
 *   "organization": {
 *     "id": 12,
 *     "name": "Capsearch Advisory",
 *     "ident": "capsearch-advisory"
 *   }
 * }
 *
 * Example 401 response:
 * { "error": "Invalid client context" }
 */
export async function getCapsearchSession(): Promise<CapsearchSession | null> {
  return fetchSession();
}

/**
 * Session bootstrap flow:
 * 1) GET /api/auth/me
 * 2) POST /api/auth/session-token
 *
 * POST /api/auth/session-token example responses:
 * - 200: { "ok": true } + Set-Cookie: capsearch_access_token, capsearch_refresh_token
 * - 401: { "error": "No active Symfony session" }
 *
 * POST /api/auth/refresh example responses:
 * - 200: { "ok": true } + Set-Cookie: rotated access/refresh cookies
 * - 401: { "error": "Missing refresh token" } or { "error": "Invalid refresh token" }
 */
export async function ensureCapsearchSession(): Promise<CapsearchSession | null> {
  const current = await fetchSession();
  if (current) {
    return current;
  }

  try {
    await fetch(apiUrl("/api/auth/session-token"), {
      method: "POST",
      credentials: "include",
    });
  } catch {
    return null;
  }

  const withSessionToken = await fetchSession();
  if (withSessionToken) {
    return withSessionToken;
  }

  let refreshed: Response;
  try {
    refreshed = await fetch(apiUrl("/api/auth/refresh"), {
      method: "POST",
      credentials: "include",
    });
  } catch {
    return null;
  }

  if (!refreshed.ok) {
    return null;
  }

  return fetchSession();
}

/**
 * Diagnostic endpoint sequence and typical statuses:
 * - GET /api/auth/me -> 200 or 401
 * - POST /api/auth/session-token -> 200 or 401
 * - GET /api/auth/me -> 200 or 401
 * - POST /api/auth/refresh -> 200 or 401
 * - GET /api/auth/me -> 200 or 401
 */
export async function getCapsearchAuthDiagnostics(): Promise<AuthDiagnostics> {
  const meBefore = await fetchStatus("/api/auth/me", { method: "GET" });
  const sessionToken = await fetchStatus("/api/auth/session-token", { method: "POST" });
  const meAfterSessionToken = await fetchStatus("/api/auth/me", { method: "GET" });
  const refresh = await fetchStatus("/api/auth/refresh", { method: "POST" });
  const meAfterRefresh = await fetchStatus("/api/auth/me", { method: "GET" });

  return {
    meBefore,
    sessionToken,
    meAfterSessionToken,
    refresh,
    meAfterRefresh,
  };
}

export async function getCapsearchAuthDebugTrace(): Promise<AuthDebugTrace> {
  const startedAt = new Date().toISOString();
  const steps: AuthDebugStep[] = [];

  steps.push(await fetchDebugStep("/api/auth/me", "GET"));
  steps.push(await fetchDebugStep("/api/auth/session-token", "POST"));
  steps.push(await fetchDebugStep("/api/auth/me", "GET"));
  steps.push(await fetchDebugStep("/api/auth/refresh", "POST"));
  steps.push(await fetchDebugStep("/api/auth/me", "GET"));

  return {
    startedAt,
    finishedAt: new Date().toISOString(),
    steps,
  };
}

/**
 * Generic authenticated fetch against Capsearch API.
 *
 * If first call returns 401:
 * - POST /api/auth/refresh
 *   - 200: retry original request once
 *   - 401: return original 401 response
 *
 * Example protected API response shape (for /api/requests/my):
 * {
 *   "items": [
 *     {
 *       "id": 1001,
 *       "name": "Working capital",
 *       "statusCatId": 3,
 *       "createdAt": "2026-05-10T11:20:00+00:00",
 *       "updatedAt": "2026-05-12T08:45:00+00:00",
 *       "totalRequirement": 250000,
 *       "percentComplete": 60
 *     }
 *   ]
 * }
 */
export async function capsearchFetch(input: string, init: RequestInit = {}) {
  const response = await fetch(apiUrl(input), {
    ...init,
    credentials: "include",
    headers: init.headers,
  });

  if (response.status !== 401) {
    return response;
  }

  const refreshed = await fetch(apiUrl("/api/auth/refresh"), {
    method: "POST",
    credentials: "include",
  });

  if (!refreshed.ok) {
    return response;
  }

  return fetch(apiUrl(input), {
    ...init,
    credentials: "include",
    headers: init.headers,
  });
}

/**
 * POST /api/auth/logout
 *
 * Example 200 response:
 * { "ok": true }
 *
 * Side effect:
 * - clears capsearch_access_token + capsearch_refresh_token cookies
 */
export async function logoutCapsearchSession() {
  await fetch(apiUrl("/api/auth/logout"), {
    method: "POST",
    credentials: "include",
  });
}

async function fetchSession(): Promise<CapsearchSession | null> {
  let response: Response;
  try {
    response = await fetch(apiUrl("/api/auth/me"), {
      method: "GET",
      credentials: "include",
    });
  } catch {
    return null;
  }

  if (!response.ok) {
    return null;
  }

  return response.json();
}

async function fetchStatus(path: string, init: RequestInit): Promise<number | "network_error"> {
  try {
    const response = await fetch(apiUrl(path), {
      ...init,
      credentials: "include",
    });

    return response.status;
  } catch {
    return "network_error";
  }
}

async function fetchDebugStep(path: string, method: "GET" | "POST"): Promise<AuthDebugStep> {
  const requestUrl = apiUrl(path);
  console.log("[capsearch-auth] request", { method, path, url: requestUrl });

  try {
    const response = await fetch(requestUrl, {
      method,
      credentials: "include",
    });

    let bodySnippet = "";
    try {
      bodySnippet = (await response.text()).slice(0, 300);
    } catch {
      bodySnippet = "";
    }

    console.log("[capsearch-auth] response", {
      method,
      path,
      status: response.status,
      ok: response.ok,
      bodySnippet,
    });

    return {
      path,
      method,
      status: response.status,
      ok: response.ok,
      bodySnippet,
    };
  } catch {
    console.error("[capsearch-auth] network_error", { method, path });
    return {
      path,
      method,
      status: "network_error",
      ok: false,
      bodySnippet: "",
    };
  }
}
