/**
 * API Client entry point
 * Export configured API client, generated functions, and friendly aliases.
 */

type AxiosOptions<T extends (...args: never[]) => unknown> = Parameters<T>[2];

import {
  deleteClustersClusterId,
  deleteClustersClusterIdInstancesInstanceId,
  deleteRegistriesRegistryId,
  getClusters,
  getClustersClusterId,
  getClustersClusterIdHealth,
  getClustersClusterIdInstances,
  getClustersClusterIdInstancesInstanceId,
  getClustersClusterIdInstancesInstanceIdEntries,
  getMonitoringClusters,
  getMonitoringClustersClusterId,
  getMonitoringClustersClusterIdNodes,
  getMonitoringSummary,
  getRegistries,
  getRegistriesRegistryId,
  getRegistriesRegistryIdHealth,
  getRegistriesRegistryIdRepositories,
  getRegistriesRegistryIdRepositoriesRepositoryNameArtifacts,
  getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReference,
  getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchema,
  postAuthLogin,
  postAuthRefresh,
  postAuthRegister,
  postClusters,
  postClustersClusterIdInstances,
  postRegistries,
  putClustersClusterId,
  putClustersClusterIdInstancesInstanceId,
  putRegistriesRegistryId,
} from './generated-orval/api';

import type {
  DeleteClustersClusterIdInstancesInstanceIdPathParameters,
  DeleteClustersClusterIdPathParameters,
  DeleteRegistriesRegistryIdPathParameters,
  GetClustersClusterIdInstancesInstanceIdPathParameters,
  GetClustersClusterIdInstancesPathParameters,
  GetRegistriesRegistryIdHealthPathParameters,
  GetRegistriesRegistryIdPathParameters,
  GetRegistriesRegistryIdRepositoriesPathParameters,
  GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsPathParameters,
  GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferencePathParameters,
  GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchemaPathParameters,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoArtifactResponse as GeneratedArtifactResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoAuthResponse as GeneratedAuthResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoClusterMetricsResponse as GeneratedClusterMetricsResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoClusterResponse as GeneratedClusterResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoCreateClusterRequest as GeneratedCreateClusterRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoCreateInstanceRequest as GeneratedCreateInstanceRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoCreateRegistryRequest as GeneratedCreateRegistryRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceEntryResponse as GeneratedInstanceEntry,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceResponse as GeneratedInstanceResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoLoginRequest as GeneratedLoginRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoMonitoringSummaryResponse as GeneratedMonitoringSummary,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoNodeMetricsResponse as GeneratedNodeMetricsResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRefreshTokenRequest as GeneratedRefreshTokenRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRegisterRequest as GeneratedRegisterRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRegistryHealthResponse as GeneratedRegistryHealthResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRegistryResponse as GeneratedRegistryResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRepositoryListResponse as GeneratedRepositoryListResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoTagResponse as GeneratedTagResponse,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUpdateClusterRequest as GeneratedUpdateClusterRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUpdateInstanceRequest as GeneratedUpdateInstanceRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUpdateRegistryRequest as GeneratedUpdateRegistryRequest,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUserResponse as GeneratedUserResponse,
  PutClustersClusterIdInstancesInstanceIdPathParameters,
  PutClustersClusterIdPathParameters,
  PutRegistriesRegistryIdPathParameters,
} from './generated-orval/api.schemas';

import { AXIOS_INSTANCE, customAxiosInstance } from './axios-mutator';

import {
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceResponseLastOperation as GeneratedInstanceLastOperationEnum,
  GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceResponseStatus as GeneratedInstanceStatusEnum,
} from './generated-orval/api.schemas';

export { AXIOS_INSTANCE, customAxiosInstance, setAuthToken } from './axios-mutator';
export { keysToCamel, keysToSnake, snakeToCamel, camelToSnake } from '@/shared/utils/case-converter';

// Re-export raw generated APIs/types for advanced usages
export * from './generated-orval/api';
export type * from './generated-orval/api.schemas';

// ---------- Friendly type aliases ----------
export type AuthResponse = GeneratedAuthResponse;
export type RegisterBody = GeneratedRegisterRequest;
export type AdminCreateUserRequest = RegisterBody & {
  role?: string;
  workspaceId?: string;
  namespace?: string;
  defaultClusterId?: string;
  quotaCpu?: string;
  quotaMemory?: string;
  quotaGpu?: string;
  quotaGpuMemory?: string;
  isActive?: boolean;
  mustChangePassword?: boolean;
};
export type LoginBody = GeneratedLoginRequest;
export type RefreshTokenBody = GeneratedRefreshTokenRequest;
export type UserResponse = GeneratedUserResponse & {
  role?: string;
  workspaceId?: string;
  workspaceName?: string;
  namespace?: string;
  defaultClusterId?: string;
  quotaCpu?: string;
  quotaMemory?: string;
  quotaGpu?: string;
  quotaGpuMemory?: string;
  isActive?: boolean;
  mustChangePassword?: boolean;
};
export type UpdateUserRequest = {
  role?: string;
  workspaceId?: string;
  namespace?: string;
  defaultClusterId?: string;
  quotaCpu?: string;
  quotaMemory?: string;
  quotaGpu?: string;
  quotaGpuMemory?: string;
  isActive?: boolean;
  mustChangePassword?: boolean;
};
export type ValuesYamlResponse = { valuesYaml: string };

export type ClusterResponse = GeneratedClusterResponse;
export type CreateClusterRequest = GeneratedCreateClusterRequest;
export type UpdateClusterRequest = GeneratedUpdateClusterRequest;

export type RegistryResponse = GeneratedRegistryResponse;
export type CreateRegistryRequest = GeneratedCreateRegistryRequest;
export type UpdateRegistryRequest = GeneratedUpdateRegistryRequest;
export type RegistryHealthResponse = GeneratedRegistryHealthResponse;

export type InstanceResponse = GeneratedInstanceResponse & {
  ownerId?: string;
  ownerUsername?: string;
};
export type CreateInstanceRequest = GeneratedCreateInstanceRequest;
export type UpdateInstanceRequest = GeneratedUpdateInstanceRequest;
export type InstanceEntry = GeneratedInstanceEntry;
export type InstanceDiagnosticsResponse = {
  instanceName?: string;
  namespace?: string;
  collectedAt?: string;
  pods?: Array<{
    name?: string;
    namespace?: string;
    phase?: string;
    nodeName?: string;
    podIp?: string;
    hostIp?: string;
    restartCount?: number;
    containers?: Array<{
      name?: string;
      image?: string;
      ready?: boolean;
      restartCount?: number;
      state?: string;
      reason?: string;
      message?: string;
    }>;
    conditions?: Array<{ type?: string; status?: string; reason?: string; message?: string }>;
    creationTimestamp?: string;
  }>;
  services?: Array<{
    name?: string;
    namespace?: string;
    type?: string;
    clusterIP?: string;
    ports?: Array<{ name?: string; protocol?: string; port?: number; targetPort?: string; nodePort?: number }>;
  }>;
  events?: Array<{
    type?: string;
    reason?: string;
    message?: string;
    involvedKind?: string;
    involvedName?: string;
    count?: number;
    firstTimestamp?: string;
    lastTimestamp?: string;
  }>;
  logs?: Array<{ pod?: string; container?: string; tailLines?: number; log?: string; error?: string }>;
};
export const INSTANCE_STATUS = GeneratedInstanceStatusEnum;
export type InstanceStatus = NonNullable<InstanceResponse['status']>;
export const INSTANCE_LAST_OPERATION = GeneratedInstanceLastOperationEnum;
export type InstanceLastOperation = NonNullable<InstanceResponse['lastOperation']>;

export type ArtifactResponse = GeneratedArtifactResponse;
export type ArtifactListItem = GeneratedTagResponse;
export type ListRepositories200Item =
  | {
      name?: string;
      artifact_count?: number;
      artifactCount?: number;
    }
  | string;
export type RepositoryListResponse = GeneratedRepositoryListResponse;
export type ListArtifactsFilter = 'all' | 'chart' | 'image' | 'other';

export type ClusterMonitoring = GeneratedClusterMetricsResponse;
export type ClusterMonitoringStatus = ClusterMonitoring['status'];
export type MonitoringSummary = GeneratedMonitoringSummary;
export type NodeMetricsResponse = GeneratedNodeMetricsResponse;

// ---------- Friendly function aliases ----------
export const login = postAuthLogin;
export const register = postAuthRegister;
export const refreshAuth = postAuthRefresh;
export const fetchAuthStatus = () =>
  AXIOS_INSTANCE.get<{ needsSetup: boolean; hasUsers: boolean }>("/auth/status").then((r) => r.data);
export const setupInitialAdmin = (data: { username: string; password: string; email?: string }) =>
  AXIOS_INSTANCE.post<{ accessToken: string; refreshToken: string }>("/auth/setup", data).then((r) => r.data);
export const listUsers = () => customAxiosInstance<UserResponse[]>({ url: "/users", method: "GET" });
export const createUser = (data: AdminCreateUserRequest) =>
  customAxiosInstance<UserResponse>({ url: "/users", method: "POST", data });
export const updateUser = (userId: string, data: UpdateUserRequest) =>
  customAxiosInstance<UserResponse>({ url: `/users/${encodeURIComponent(userId)}`, method: "PUT", data });
export const deleteUser = (userId: string) =>
  customAxiosInstance<void>({ url: `/users/${encodeURIComponent(userId)}`, method: "DELETE" });

export const listClusters = getClusters;
export const createCluster = postClusters;
export const getCluster = getClustersClusterId;
export const updateCluster = putClustersClusterId;
export const deleteCluster = deleteClustersClusterId;
export const getClusterHealth = getClustersClusterIdHealth;

export const listInstances = getClustersClusterIdInstances;
export const createInstance = postClustersClusterIdInstances;
export const getInstance = getClustersClusterIdInstancesInstanceId;
export const updateInstance = putClustersClusterIdInstancesInstanceId;
export const deleteInstance = deleteClustersClusterIdInstancesInstanceId;
export const listInstanceEntries = getClustersClusterIdInstancesInstanceIdEntries;
export const scaleInstance = (
  clusterId: string,
  instanceId: string,
  body: { replicas: number; workload?: string },
) => {
  return customAxiosInstance<{ instance: InstanceResponse; replicas: number; message: string }>({
    url: `/clusters/${encodeURIComponent(clusterId)}/instances/${encodeURIComponent(instanceId)}/scale`,
    method: "POST",
    data: body,
  });
};
export const getInstanceValuesDiff = (
  clusterId: string,
  instanceId: string,
) => {
  return customAxiosInstance<{ current: Record<string, unknown>; defaults: Record<string, unknown> }>({
    url: `/clusters/${encodeURIComponent(clusterId)}/instances/${encodeURIComponent(instanceId)}/values-diff`,
    method: "GET",
  });
};
export const getInstanceDiagnostics = (
  params: { clusterId: string; instanceId: string },
  options?: { tailLines?: number },
) =>
  customAxiosInstance<InstanceDiagnosticsResponse>({
    url: `/clusters/${encodeURIComponent(params.clusterId)}/instances/${encodeURIComponent(params.instanceId)}/diagnostics`,
    method: "GET",
    params: options?.tailLines ? { tailLines: options.tailLines } : undefined,
  });

/**
 * Stream pod logs via SSE from the backend.
 * Returns an AbortController to cancel the stream at any time.
 */
export function streamInstanceLogs(
  clusterId: string,
  instanceId: string,
  pod: string,
  container: string,
  tailLines: number = 200,
  onLine: (line: string) => void,
  onDone: () => void,
  onError: (err: Error) => void,
): AbortController {
  const controller = new AbortController();
  const baseUrl = AXIOS_INSTANCE.defaults.baseURL ?? "/api/v1";
  const authHeader = AXIOS_INSTANCE.defaults.headers.common["Authorization"] as string | undefined;

  const params = new URLSearchParams({ pod, container, tailLines: String(tailLines) });
  const url = `${baseUrl}/clusters/${encodeURIComponent(clusterId)}/instances/${encodeURIComponent(instanceId)}/logs/stream?${params}`;

  const headers: Record<string, string> = { Accept: "text/event-stream" };
  if (authHeader) {
    headers["Authorization"] = authHeader;
  }

  fetch(url, { headers, signal: controller.signal })
    .then(async (response) => {
      if (!response.ok) {
        const text = await response.text().catch(() => response.statusText);
        onError(new Error(`HTTP ${response.status}: ${text}`));
        return;
      }
      const reader = response.body?.getReader();
      if (!reader) {
        onError(new Error("ReadableStream not supported"));
        return;
      }
      const decoder = new TextDecoder();
      let buffer = "";
      try {
        while (true) {
          const { done, value } = await reader.read();
          if (done) break;
          buffer += decoder.decode(value, { stream: true });
          const lines = buffer.split("\n");
          // Keep the last potentially-incomplete line in the buffer
          buffer = lines.pop() ?? "";
          for (const line of lines) {
            const trimmed = line.trim();
            if (!trimmed || !trimmed.startsWith("data:")) continue;
            const data = trimmed.slice(5).trim();
            if (data === "[DONE]") {
              onDone();
              return;
            }
            if (data.startsWith("[ERROR]")) {
              onError(new Error(data.slice(7).trim()));
              continue;
            }
            onLine(data);
          }
        }
      } catch (err: unknown) {
        if (err instanceof DOMException && err.name === "AbortError") {
          // Stream was intentionally cancelled - not an error
          return;
        }
        onError(err instanceof Error ? err : new Error(String(err)));
      }
      onDone();
    })
    .catch((err: unknown) => {
      if (err instanceof DOMException && err.name === "AbortError") {
        return;
      }
      onError(err instanceof Error ? err : new Error(String(err)));
    });

  return controller;
}

export const listRegistries = getRegistries;
export const createRegistry = postRegistries;
export const getRegistry = getRegistriesRegistryId;
export const updateRegistry = putRegistriesRegistryId;
export const deleteRegistry = deleteRegistriesRegistryId;
export const checkRegistryHealth = getRegistriesRegistryIdHealth;

export const listRepositories = (
  params: GetRegistriesRegistryIdRepositoriesPathParameters,
  options?: { artifactType?: 'chart' | 'all' },
) =>
  getRegistriesRegistryIdRepositories(params, {
    params: options?.artifactType ? { artifact_type: options.artifactType } : undefined,
  });
type ListArtifactsRequestOptions = AxiosOptions<typeof getRegistriesRegistryIdRepositoriesRepositoryNameArtifacts>;

export const listArtifacts = (
  params: GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsPathParameters,
  options?: { filter?: ListArtifactsFilter },
  axiosOptions?: ListArtifactsRequestOptions,
) => {
  const query =
    options?.filter && options.filter !== 'all'
      ? { media_type: options.filter }
      : undefined;
  return getRegistriesRegistryIdRepositoriesRepositoryNameArtifacts(params, query, axiosOptions);
};

export const getArtifact = getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReference;
export const getValuesSchema = getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchema;
export const getValuesYaml = (params: GetValuesSchemaPathParameters) =>
  customAxiosInstance<ValuesYamlResponse>({
    url: `/registries/${encodeURIComponent(params.registryId)}/repositories/${encodeURIComponent(params.repositoryName)}/artifacts/${encodeURIComponent(params.reference)}/values-yaml`,
    method: "GET",
  });

export const listClusterMonitoring = getMonitoringClusters;
export const getClusterMonitoring = getMonitoringClustersClusterId;
export const getClusterNodeMetrics = getMonitoringClustersClusterIdNodes;
export const getMonitoringSummaryData = getMonitoringSummary;

// Re-export parameter types with friendly names for caller convenience
export type DeleteClusterPathParameters = DeleteClustersClusterIdPathParameters;
export type UpdateClusterPathParameters = PutClustersClusterIdPathParameters;
export type ClusterInstancesPathParameters = GetClustersClusterIdInstancesPathParameters;
export type InstancePathParameters = GetClustersClusterIdInstancesInstanceIdPathParameters;
export type UpdateInstancePathParameters = PutClustersClusterIdInstancesInstanceIdPathParameters;
export type DeleteInstancePathParameters = DeleteClustersClusterIdInstancesInstanceIdPathParameters;
export type RegistryPathParameters = GetRegistriesRegistryIdPathParameters;
export type UpdateRegistryPathParameters = PutRegistriesRegistryIdPathParameters;
export type DeleteRegistryPathParameters = DeleteRegistriesRegistryIdPathParameters;
export type RegistryHealthPathParameters = GetRegistriesRegistryIdHealthPathParameters;
export type ListRepositoriesPathParameters = GetRegistriesRegistryIdRepositoriesPathParameters;
export type ListArtifactsPathParameters = GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsPathParameters;
export type ListArtifactsParams = { filter?: ListArtifactsFilter };
export type GetArtifactPathParameters = GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferencePathParameters;
export type GetValuesSchemaPathParameters = GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchemaPathParameters;
