/**
 * Delivery Platform API client — Torbat Driver (real backend only).
 * Browser → /api/delivery BFF; SSR → direct upstream :8007
 */

import { getValidAccessToken, refreshSession } from "@/lib/auth";
import type {
  CapabilitiesResponse,
  DriverListResponse,
  HealthResponse,
  ListParams,
  MetricsResponse,
  PaginatedList,
  PermissionsCatalogResponse,
} from "@/modules/delivery/types";

const DELIVERY_BASE =
  typeof window !== "undefined"
    ? "/api/delivery"
    : process.env.DELIVERY_SERVICE_URL ||
      process.env.NEXT_PUBLIC_DELIVERY_API_URL ||
      "http://localhost:8007";

export class DeliveryApiError extends Error {
  constructor(
    public status: number,
    public code: string,
    message: string
  ) {
    super(message);
    this.name = "DeliveryApiError";
  }
}

type RequestOptions = RequestInit & { tenantId: string; auth?: boolean };

async function request<T>(path: string, options: RequestOptions): Promise<T> {
  const { tenantId, auth = true, headers: customHeaders, ...init } = options;
  const headers = new Headers(customHeaders);
  if (!headers.has("Content-Type") && init.body) {
    headers.set("Content-Type", "application/json");
  }
  headers.set("X-Tenant-ID", tenantId);
  if (auth) {
    const token = await getValidAccessToken();
    if (token) headers.set("Authorization", `Bearer ${token}`);
  }

  const url = path.startsWith("http")
    ? path
    : `${DELIVERY_BASE.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;

  let res: Response;
  try {
    res = await fetch(url, { ...init, headers });
  } catch (err) {
    const detail = err instanceof Error ? err.message : "network_error";
    throw new Error(`اتصال به سرویس تربت درایور برقرار نشد (${url}) — ${detail}`);
  }

  if (res.status === 401 && auth) {
    const refreshed = await refreshSession({ force: true });
    if (refreshed) {
      headers.set("Authorization", `Bearer ${refreshed}`);
      res = await fetch(url, { ...init, headers });
    }
  }

  if (!res.ok) {
    const body = await res.json().catch(() => ({}));
    throw new DeliveryApiError(
      res.status,
      body?.error?.code || body?.detail || "unknown_error",
      body?.error?.message || body?.detail || res.statusText
    );
  }
  if (res.status === 204) return undefined as T;
  return res.json() as Promise<T>;
}

function qs(params?: Record<string, string | number | boolean | undefined | null>) {
  if (!params) return "";
  const sp = new URLSearchParams();
  Object.entries(params).forEach(([k, v]) => {
    if (v !== undefined && v !== null && v !== "") sp.set(k, String(v));
  });
  const s = sp.toString();
  return s ? `?${s}` : "";
}

function crudResource(basePath: string) {
  return {
    list: (tenantId: string, params?: ListParams) =>
      request<Record<string, unknown>[]>(`${basePath}${qs(params)}`, { tenantId }),
    get: (tenantId: string, id: string) =>
      request<Record<string, unknown>>(`${basePath}/${id}`, { tenantId }),
    create: (tenantId: string, body: Record<string, unknown>) =>
      request<Record<string, unknown>>(basePath, {
        tenantId,
        method: "POST",
        body: JSON.stringify(body),
      }),
    update: (tenantId: string, id: string, body: Record<string, unknown>) =>
      request<Record<string, unknown>>(`${basePath}/${id}`, {
        tenantId,
        method: "PATCH",
        body: JSON.stringify(body),
      }),
    remove: (tenantId: string, id: string) =>
      request<Record<string, unknown>>(`${basePath}/${id}/delete`, {
        tenantId,
        method: "POST",
      }),
  };
}

export const deliveryApi = {
  health: (): Promise<HealthResponse> =>
    fetch(`${DELIVERY_BASE}/health`).then((r) => r.json()),

  capabilities: (): Promise<CapabilitiesResponse> =>
    fetch(`${DELIVERY_BASE}/capabilities`).then((r) => r.json()),

  metrics: (): Promise<MetricsResponse> =>
    fetch(`${DELIVERY_BASE}/metrics`).then((r) => r.json()),

  permissions: {
    catalog: (tenantId: string) =>
      request<PermissionsCatalogResponse>(`/api/v1/permissions/catalog`, { tenantId }),
  },

  organizations: crudResource("/api/v1/organizations"),
  hubs: crudResource("/api/v1/hubs"),
  externalProviders: crudResource("/api/v1/external-providers"),
  routingEngines: crudResource("/api/v1/routing-engines"),
  configurations: crudResource("/api/v1/configurations"),

  settings: {
    list: (tenantId: string, params?: ListParams) =>
      request<Record<string, unknown>[]>(`/api/v1/settings${qs(params)}`, { tenantId }),
    upsert: (tenantId: string, body: Record<string, unknown>) =>
      request<Record<string, unknown>>(`/api/v1/settings`, {
        tenantId,
        method: "PUT",
        body: JSON.stringify(body),
      }),
  },

  audit: {
    list: (
      tenantId: string,
      params: { entity_type: string; entity_id: string; limit?: number }
    ) => request<Record<string, unknown>[]>(`/api/v1/audit${qs(params)}`, { tenantId }),
  },

  drivers: {
    list: (tenantId: string, params?: ListParams) =>
      request<DriverListResponse | Record<string, unknown>[]>(
        `/api/v1/drivers${qs(params)}`,
        { tenantId }
      ).then(normalizeDriverList),
    get: (tenantId: string, id: string) =>
      request<Record<string, unknown>>(`/api/v1/drivers/${id}`, { tenantId }),
    create: (tenantId: string, body: Record<string, unknown>) =>
      request<Record<string, unknown>>(`/api/v1/drivers`, {
        tenantId,
        method: "POST",
        body: JSON.stringify(body),
      }),
    update: (tenantId: string, id: string, body: Record<string, unknown>) =>
      request<Record<string, unknown>>(`/api/v1/drivers/${id}`, {
        tenantId,
        method: "PATCH",
        body: JSON.stringify(body),
      }),
    remove: (tenantId: string, id: string) =>
      request<Record<string, unknown>>(`/api/v1/drivers/${id}/delete`, {
        tenantId,
        method: "POST",
      }),
    activate: (tenantId: string, id: string, body: Record<string, unknown>) =>
      lifecycleAction(tenantId, id, "activate", body),
    suspend: (tenantId: string, id: string, body: Record<string, unknown>) =>
      lifecycleAction(tenantId, id, "suspend", body),
    resume: (tenantId: string, id: string, body: Record<string, unknown>) =>
      lifecycleAction(tenantId, id, "resume", body),
    deactivate: (tenantId: string, id: string, body: Record<string, unknown>) =>
      lifecycleAction(tenantId, id, "deactivate", body),
    block: (tenantId: string, id: string, body: Record<string, unknown>) =>
      lifecycleAction(tenantId, id, "block", body),
    unblock: (tenantId: string, id: string, body: Record<string, unknown>) =>
      lifecycleAction(tenantId, id, "unblock", body),
    archive: (tenantId: string, id: string, body: Record<string, unknown>) =>
      lifecycleAction(tenantId, id, "archive", body),
    lifecycle: (tenantId: string, id: string) =>
      request<Record<string, unknown>[]>(`/api/v1/drivers/${id}/lifecycle`, { tenantId }),
    credentials: {
      list: (tenantId: string, driverId: string) =>
        request<Record<string, unknown>[]>(`/api/v1/drivers/${driverId}/credentials`, {
          tenantId,
        }),
      create: (tenantId: string, driverId: string, body: Record<string, unknown>) =>
        request<Record<string, unknown>>(`/api/v1/drivers/${driverId}/credentials`, {
          tenantId,
          method: "POST",
          body: JSON.stringify(body),
        }),
    },
    documents: {
      list: (tenantId: string, driverId: string) =>
        request<Record<string, unknown>[]>(`/api/v1/drivers/${driverId}/documents`, { tenantId }),
      create: (tenantId: string, driverId: string, body: Record<string, unknown>) =>
        request<Record<string, unknown>>(`/api/v1/drivers/${driverId}/documents`, {
          tenantId,
          method: "POST",
          body: JSON.stringify(body),
        }),
    },
  },
};

function lifecycleAction(
  tenantId: string,
  id: string,
  action: string,
  body: Record<string, unknown>
) {
  return request<Record<string, unknown>>(`/api/v1/drivers/${id}/${action}`, {
    tenantId,
    method: "POST",
    body: JSON.stringify(body),
  });
}

function normalizeDriverList(
  data: DriverListResponse | Record<string, unknown>[]
): PaginatedList<Record<string, unknown>> {
  if (Array.isArray(data)) {
    return { items: data, total: data.length, page: 1, page_size: data.length };
  }
  return {
    items: data.items ?? [],
    total: data.total ?? 0,
    page: data.page ?? 1,
    page_size: data.page_size ?? 20,
  };
}
