import axios from "axios";

// --- ENV CONFIG ---
const API_BASE_URL =
  import.meta.env.VITE_API_BASE_URL || "http://localhost:8000";

const LOGIN_PATH = import.meta.env.VITE_LOGIN_PATH || "/login";


// --- ERROR EVENT BUS ---
const ERROR_EVENT = "api:error";
type ApiErrorDetail = {
  message: string;
  status?: number;
  url?: string;
  data?: unknown;
};

// Use interface instead of arrow function types for readability
interface ApiErrorHandler {
  (e: CustomEvent<ApiErrorDetail>): void;
}

function notifyError(detail: ApiErrorDetail) {
  window.dispatchEvent(new CustomEvent<ApiErrorDetail>(ERROR_EVENT, { detail }));
  // eslint-disable-next-line no-console
  console.error("[API ERROR]", detail);
}
function onError(handler: ApiErrorHandler) {
  const wrapped = handler as EventListener;
  window.addEventListener(ERROR_EVENT, wrapped as EventListener);

  return () => window.removeEventListener(ERROR_EVENT, wrapped);
}

// --- AXIOS INSTANCES ---
// Always send cookies. Django will set auth cookies; browser will include them automatically.
function createAxios(baseURL: string): any {
  const instance = axios.create({
    baseURL,
    withCredentials: true, // cookies
    headers: {
      "Content-Type": "application/json",
    },
    timeout: 20000,
  });
  return instance;
}

// Use a single behavior for both: cookies are always sent
const apiPublic = createAxios(API_BASE_URL);
const apiAuth = createAxios(API_BASE_URL);


// --- REQUEST INTERCEPTOR (PUBLIC) ---
// Ensure no Authorization header is ever sent by the public client
apiPublic.interceptors.request.use(function (config: any) {
  if (config?.headers && (config.headers as any).Authorization) {
    delete (config.headers as any).Authorization;
  }

  return config;
});

// --- REQUEST INTERCEPTOR (AUTH) ---
// Do not attach Authorization header; rely on cookies set by Django.
apiAuth.interceptors.request.use(function (config: any) {
  (config as any)._retryCount = (config as any)._retryCount || 0;

  return config;
});

// --- RESPONSE INTERCEPTOR (AUTH) ---
// Simplified: on 401, redirect to login. Server manages refresh via cookies.
apiAuth.interceptors.response.use(
  function (response: any) {
    return response;
  },
  async function (error: any) {
    if (!error.response) {
      alert("Backend connection is unavailable. Please check your network.");

      notifyError({
        message: "Network error or backend unavailable",
        url: error.config?.url,
      });

      return Promise.reject(error);
    }

    const status = error.response.status;
    if (status === 401) {
      ClearTokens();
      window.location.assign(LOGIN_PATH);
      return Promise.reject(error);
    }

    notifyError({
      message:
        (error.response.data as any)?.detail ||
        (error.response.data as any)?.message ||
        `Request failed with status ${status}`,
      status,
      url: error.config?.url,
      data: error.response.data,
    });
    return Promise.reject(error);
  }
);

// --- PUBLIC CLIENT: still emits errors and alerts on network failure ---
apiPublic.interceptors.response.use(
  function (response: any) {
    return response;
  },
  async function (error: any) {
    if (!error.response) {
      alert("Backend connection is unavailable. Please check your network.");
      notifyError({
        message: "Network error or backend unavailable",
        url: error.config?.url,
      });
      return Promise.reject(error);
    }
    notifyError({
      message:
        (error.response.data as any)?.detail ||
        (error.response.data as any)?.message ||
        `Request failed with status ${error.response.status}`,
      status: error.response.status,
      url: error.config?.url,
      data: error.response.data,
    });
    return Promise.reject(error);
  }
);




function Logout() {
  try {
    const LogOutResponse = apiAuth.post("/api/logout/");

    if (LogOutResponse.body.detail != "Logout successful") {
      throw new Error("Logout failed");
    }

    ClearTokens();

  } catch (error) {
    console.error("Error during logout:", error);
  }
}

function ClearTokens(){
  document.cookie = "access_token=; Max-Age=0; path=/";
  document.cookie = "refresh_token=; Max-Age=0; path=/";
}


// --- EXPORT DEFAULT API WRAPPER ---
const Client = {
  // Axios instances
  auth: apiAuth,
  public: apiPublic,

  Logout,

  // Error subscription
  onError,
};

export default Client;

/**
USAGE EXAMPLES (TypeScript/React)

Import the client
--------------------------------------------------
import Client from "@/api/Client";


Login: obtain tokens and persist to cookies
--------------------------------------------------
async function login(username: string, password: string) {
  // SimpleJWT default login endpoint (adjust if your backend differs)
  // Example backend endpoint: POST /api/token/ -> { access, refresh }
  const res = await Client.public.post("/api/token/", { username, password });
  const { access, refresh } = res.data;
  Client.setTokens(access, refresh);
  // After this, Client.auth will automatically attach Authorization header
  // and refresh when receiving a 401 (up to 2 retries).
}


Public request (no cookies, no Authorization)
--------------------------------------------------
// The public client does NOT send cookies or Authorization.
async function listPublicItems() {
  const res = await Client.public.get("/api/public/items/");
  return res.data;
}


Authenticated requests (auto Bearer header + refresh on 401)
--------------------------------------------------
async function fetchProfile() {
  const res = await Client.auth.get("/api/users/me/");
  return res.data;
}

async function updateProfile(payload: { first_name?: string; last_name?: string }) {
  const res = await Client.auth.patch("/api/users/me/", payload);
  return res.data;
}


Global error handling (UI notifications)
--------------------------------------------------
import { useEffect } from "react";

function useApiErrors(showToast: (msg: string) => void) {
  useEffect(function () {
    const unsubscribe = Client.onError(function (e) {
      const { message, status } = e.detail;
      showToast(status ? String(status) + ": " + message : message);
    });
    return unsubscribe;
  }, [showToast]);
}

// Note: Network connectivity issues trigger an alert and also dispatch api:error.
// All errors are logged to console for developers.


Logout
--------------------------------------------------
function logout() {
  Client.clearTokens();
  window.location.assign("/login");
}


Route protection (PrivateRoute)
--------------------------------------------------
// If you created src/routes/PrivateRoute.tsx, wrap your protected routes with it.
// PrivateRoute checks for "access_token" cookie presence and redirects to /login if missing.

// Example:
// <Routes>
//   <Route element={<PrivateRoute />} >
//     <Route element={<MainLayout />}>
//       <Route path="/" element={<Dashboard />} />
//       <Route path="/profile" element={<Profile />} />
//     </Route>
//   </Route>
//   <Route path="/login" element={<Login />} />
// </Routes>


Refresh and retry flow (what happens on 401)
--------------------------------------------------
// 1) Client.auth request receives 401 from backend
// 2) Client tries to refresh access token using refresh_token cookie
// 3) If refresh succeeds, original request is retried (max 2 times)
// 4) If still 401 (or no refresh token), tokens are cleared and user is redirected to /login


Environment variables (optional overrides)
--------------------------------------------------
// VITE_API_BASE_URL      default: "http://localhost:8000"
// VITE_API_REFRESH_URL   default: "/api/token/refresh/"
// VITE_LOGIN_PATH        default: "/login"
*/
