import type {
  AdminGatewayTask,
  AuthResponse,
  AuthUser,
  BaseModelCatalogItem,
  BaseModelUpsertRequest,
  BillingSettlementListResponse,
  BillingSettlementRetryResponse,
  CatalogProvider,
  CatalogProviderUpsertRequest,
  ClientCustomizationSettings,
  ClientCustomizationSettingsUpdateRequest,
  CreatedGatewayApiKey,
  FileStorageChannel,
  FileStorageSettings,
  FileStorageSettingsUpdateRequest,
  FileStorageChannelUpsertRequest,
  GatewayAccessRuleBatchRequest,
  GatewayAccessRule,
  GatewayAccessRuleUpsertRequest,
  GatewayApiKey,
  GatewayApiKeyScopeUpdateRequest,
  GatewayAuditLog,
  GatewayRunnerPolicy,
  GatewayRunnerPolicyUpsertRequest,
	IdentityConfigurationRevision,
	IdentityConfigurationView,
	IdentityPairingExchange,
	IdentityPairingInput,
	IdentityRevisionPolicyUpdate,
  GatewayTenant,
  GatewayTenantUpsertRequest,
  GatewayNetworkProxyConfig,
  GatewayPricingEstimate,
  GatewaySkillBundleMetadata,
  GatewayTask,
  GatewayTaskParamPreprocessingLog,
  GatewayUser,
  GatewayUserUpsertRequest,
  GatewayWalletTransaction,
  IntegrationPlatform,
  ListResponse,
  ModelCatalogResponse,
  ModelRateLimitStatus,
  PlatformDynamicPriorityState,
  PlatformDynamicPriorityUpdateRequest,
  PlatformModel,
  PlayableGatewayApiKey,
  PricingRule,
  PricingRuleSet,
  PricingRuleSetUpsertRequest,
  RateLimitWindow,
  RuntimePolicySet,
  RuntimePolicySetUpsertRequest,
  SecurityEventConnectionResponse,
  UserGroup,
  UserGroupUpsertRequest,
  WalletAdjustmentResponse,
  WalletBalanceAdjustmentRequest,
  WalletRechargeRequest,
  WalletSummaryResponse,
} from '@easyai-ai-gateway/contracts';
import type { AdminTaskQuery, PlatformCreateInput, PlatformModelBindingInput, WorkspaceTaskQuery } from './types';

const API_BASE = import.meta.env.VITE_GATEWAY_API_BASE_URL ?? 'http://localhost:8088';
export const OIDC_BROWSER_SESSION_CREDENTIAL = '__easyai_gateway_oidc_browser_session__';

export interface GatewayErrorDetails {
  code?: string;
  message: string;
  requestId?: string;
  status?: number;
  taskId?: string;
}

export class GatewayApiError extends Error {
  readonly details: GatewayErrorDetails;

  constructor(details: GatewayErrorDetails | string) {
    const normalized = typeof details === 'string' ? { message: details } : details;
    super(formatGatewayErrorDetails(normalized));
    this.name = 'GatewayApiError';
    this.details = normalized;
  }

  toString() {
    return this.message;
  }
}

export interface HealthResponse {
  ok: boolean;
  service: string;
  env: string;
  identityMode?: string;
}

export async function getHealth(): Promise<HealthResponse> {
  return request<HealthResponse>('/healthz', { auth: false });
}

export async function getOpsManagementSkillMetadata(): Promise<GatewaySkillBundleMetadata> {
  return request<GatewaySkillBundleMetadata>('/api/v1/public/skills/ai-gateway-ops-management/metadata', { auth: false });
}

export async function registerLocalAccount(input: {
  username: string;
  email?: string;
  password: string;
  displayName?: string;
  invitationCode?: string;
}): Promise<AuthResponse> {
  return request<AuthResponse>('/api/v1/auth/register', {
    auth: false,
    body: input,
    method: 'POST',
  });
}

export async function loginLocalAccount(input: { account: string; password: string }): Promise<AuthResponse> {
  return request<AuthResponse>('/api/v1/auth/login', {
    auth: false,
    body: input,
    method: 'POST',
    timeoutMs: 10_000,
  });
}

export async function deleteOIDCBrowserSession(): Promise<void> {
  await request<void>('/api/v1/auth/oidc/session', {
    auth: false,
    method: 'DELETE',
  });
}

export async function getCurrentUser(token: string): Promise<AuthUser> {
  return request<AuthUser>('/api/v1/me', { token });
}

export async function listPlatforms(token: string): Promise<ListResponse<IntegrationPlatform>> {
  return request<ListResponse<IntegrationPlatform>>('/api/admin/platforms', { token });
}

export async function updatePlatformDynamicPriority(
  token: string,
  platformId: string,
  input: PlatformDynamicPriorityUpdateRequest,
): Promise<PlatformDynamicPriorityState> {
  return request<PlatformDynamicPriorityState>(`/api/admin/platforms/${platformId}/dynamic-priority`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function listModels(token: string): Promise<ListResponse<PlatformModel>> {
  return request<ListResponse<PlatformModel>>('/api/admin/models', { token });
}

export async function listPlayableModels(token: string): Promise<ListResponse<PlatformModel>> {
  return request<ListResponse<PlatformModel>>('/api/v1/models', { token });
}

export async function listModelCatalog(token: string): Promise<ModelCatalogResponse> {
  return request<ModelCatalogResponse>('/api/v1/model-catalog', { token });
}

export async function listPublicCatalogProviders(): Promise<ListResponse<CatalogProvider>> {
  return request<ListResponse<CatalogProvider>>('/api/v1/public/catalog/providers', { auth: false });
}

export async function listCatalogProviders(token: string): Promise<ListResponse<CatalogProvider>> {
  return request<ListResponse<CatalogProvider>>('/api/admin/catalog/providers', { token });
}

export async function createCatalogProvider(
  token: string,
  input: CatalogProviderUpsertRequest,
): Promise<CatalogProvider> {
  return request<CatalogProvider>('/api/admin/catalog/providers', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateCatalogProvider(
  token: string,
  providerId: string,
  input: CatalogProviderUpsertRequest,
): Promise<CatalogProvider> {
  return request<CatalogProvider>(`/api/admin/catalog/providers/${providerId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deleteCatalogProvider(token: string, providerId: string): Promise<void> {
  await request<void>(`/api/admin/catalog/providers/${providerId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listPublicBaseModels(): Promise<ListResponse<BaseModelCatalogItem>> {
  return request<ListResponse<BaseModelCatalogItem>>('/api/v1/public/catalog/base-models', { auth: false });
}

export async function listBaseModels(token: string): Promise<ListResponse<BaseModelCatalogItem>> {
  return request<ListResponse<BaseModelCatalogItem>>('/api/admin/catalog/base-models', { token });
}

export async function createBaseModel(token: string, input: BaseModelUpsertRequest): Promise<BaseModelCatalogItem> {
  return request<BaseModelCatalogItem>('/api/admin/catalog/base-models', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateBaseModel(
  token: string,
  baseModelId: string,
  input: BaseModelUpsertRequest,
): Promise<BaseModelCatalogItem> {
  return request<BaseModelCatalogItem>(`/api/admin/catalog/base-models/${baseModelId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function resetBaseModel(token: string, baseModelId: string): Promise<BaseModelCatalogItem> {
  return request<BaseModelCatalogItem>(`/api/admin/catalog/base-models/${baseModelId}/reset`, {
    method: 'POST',
    token,
  });
}

export async function resetAllBaseModels(token: string): Promise<ListResponse<BaseModelCatalogItem>> {
  return request<ListResponse<BaseModelCatalogItem>>('/api/admin/catalog/base-models/reset-all', {
    method: 'POST',
    token,
  });
}

export async function deleteBaseModel(token: string, baseModelId: string): Promise<void> {
  await request<void>(`/api/admin/catalog/base-models/${baseModelId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listPricingRules(token: string): Promise<ListResponse<PricingRule>> {
  return request<ListResponse<PricingRule>>('/api/admin/pricing/rules', { token });
}

export async function listPricingRuleSets(token: string): Promise<ListResponse<PricingRuleSet>> {
  return request<ListResponse<PricingRuleSet>>('/api/admin/pricing/rule-sets', { token });
}

export async function createPricingRuleSet(
  token: string,
  input: PricingRuleSetUpsertRequest,
): Promise<PricingRuleSet> {
  return request<PricingRuleSet>('/api/admin/pricing/rule-sets', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updatePricingRuleSet(
  token: string,
  ruleSetId: string,
  input: PricingRuleSetUpsertRequest,
): Promise<PricingRuleSet> {
  return request<PricingRuleSet>(`/api/admin/pricing/rule-sets/${ruleSetId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deletePricingRuleSet(token: string, ruleSetId: string): Promise<void> {
  await request<void>(`/api/admin/pricing/rule-sets/${ruleSetId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listRuntimePolicySets(token: string): Promise<ListResponse<RuntimePolicySet>> {
  return request<ListResponse<RuntimePolicySet>>('/api/admin/runtime/policy-sets', { token });
}

export async function getRunnerPolicy(token: string): Promise<GatewayRunnerPolicy> {
  return request<GatewayRunnerPolicy>('/api/admin/runtime/runner-policy', { token });
}

export async function updateRunnerPolicy(
  token: string,
  input: GatewayRunnerPolicyUpsertRequest,
): Promise<GatewayRunnerPolicy> {
  return request<GatewayRunnerPolicy>('/api/admin/runtime/runner-policy', {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function createRuntimePolicySet(
  token: string,
  input: RuntimePolicySetUpsertRequest,
): Promise<RuntimePolicySet> {
  return request<RuntimePolicySet>('/api/admin/runtime/policy-sets', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateRuntimePolicySet(
  token: string,
  policySetId: string,
  input: RuntimePolicySetUpsertRequest,
): Promise<RuntimePolicySet> {
  return request<RuntimePolicySet>(`/api/admin/runtime/policy-sets/${policySetId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deleteRuntimePolicySet(token: string, policySetId: string): Promise<void> {
  await request<void>(`/api/admin/runtime/policy-sets/${policySetId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listTenants(token: string): Promise<ListResponse<GatewayTenant>> {
  return request<ListResponse<GatewayTenant>>('/api/admin/tenants', { token });
}

export async function createTenant(token: string, input: GatewayTenantUpsertRequest): Promise<GatewayTenant> {
  return request<GatewayTenant>('/api/admin/tenants', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateTenant(token: string, tenantId: string, input: GatewayTenantUpsertRequest): Promise<GatewayTenant> {
  return request<GatewayTenant>(`/api/admin/tenants/${tenantId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deleteTenant(token: string, tenantId: string): Promise<void> {
  await request<void>(`/api/admin/tenants/${tenantId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listUsers(token: string): Promise<ListResponse<GatewayUser>> {
  return request<ListResponse<GatewayUser>>('/api/admin/users', { token });
}

export async function createGatewayUser(token: string, input: GatewayUserUpsertRequest): Promise<GatewayUser> {
  return request<GatewayUser>('/api/admin/users', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateGatewayUser(token: string, userId: string, input: GatewayUserUpsertRequest): Promise<GatewayUser> {
  return request<GatewayUser>(`/api/admin/users/${userId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function setUserWalletBalance(
  token: string,
  userId: string,
  input: WalletBalanceAdjustmentRequest,
): Promise<WalletAdjustmentResponse> {
  return request<WalletAdjustmentResponse>(`/api/admin/users/${userId}/wallet`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function rechargeUserWalletBalance(
  token: string,
  userId: string,
  input: WalletRechargeRequest,
): Promise<WalletAdjustmentResponse> {
  return request<WalletAdjustmentResponse>(`/api/admin/users/${userId}/wallet/recharge`, {
    body: input,
    method: 'POST',
    token,
  });
}

export async function deleteGatewayUser(token: string, userId: string): Promise<void> {
  await request<void>(`/api/admin/users/${userId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listAuditLogs(token: string): Promise<ListResponse<GatewayAuditLog>> {
  return request<ListResponse<GatewayAuditLog>>('/api/admin/audit-logs', { token });
}

export async function listUserGroups(token: string): Promise<ListResponse<UserGroup>> {
  return request<ListResponse<UserGroup>>('/api/admin/user-groups', { token });
}

export async function listCurrentUserGroups(token: string): Promise<ListResponse<UserGroup>> {
  return request<ListResponse<UserGroup>>('/api/workspace/user-groups', { token });
}

export async function createUserGroup(token: string, input: UserGroupUpsertRequest): Promise<UserGroup> {
  return request<UserGroup>('/api/admin/user-groups', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateUserGroup(token: string, groupId: string, input: UserGroupUpsertRequest): Promise<UserGroup> {
  return request<UserGroup>(`/api/admin/user-groups/${groupId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deleteUserGroup(token: string, groupId: string): Promise<void> {
  await request<void>(`/api/admin/user-groups/${groupId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listAccessRules(token: string): Promise<ListResponse<GatewayAccessRule>> {
  return request<ListResponse<GatewayAccessRule>>('/api/admin/access-rules', { token });
}

export async function listApiKeyAccessRules(token: string): Promise<ListResponse<GatewayAccessRule>> {
  return request<ListResponse<GatewayAccessRule>>('/api/v1/api-keys/access-rules', { token });
}

export async function listApiKeyAssignableModels(token: string): Promise<ListResponse<PlatformModel>> {
  return request<ListResponse<PlatformModel>>('/api/v1/api-keys/assignable-models', { token });
}

export async function createAccessRule(token: string, input: GatewayAccessRuleUpsertRequest): Promise<GatewayAccessRule> {
  return request<GatewayAccessRule>('/api/admin/access-rules', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function batchAccessRules(token: string, input: GatewayAccessRuleBatchRequest): Promise<ListResponse<GatewayAccessRule>> {
  return request<ListResponse<GatewayAccessRule>>('/api/admin/access-rules/batch', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function batchApiKeyAccessRules(token: string, input: GatewayAccessRuleBatchRequest): Promise<ListResponse<GatewayAccessRule>> {
  return request<ListResponse<GatewayAccessRule>>('/api/v1/api-keys/access-rules/batch', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateAccessRule(
  token: string,
  ruleId: string,
  input: GatewayAccessRuleUpsertRequest,
): Promise<GatewayAccessRule> {
  return request<GatewayAccessRule>(`/api/admin/access-rules/${ruleId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deleteAccessRule(token: string, ruleId: string): Promise<void> {
  await request<void>(`/api/admin/access-rules/${ruleId}`, {
    method: 'DELETE',
    token,
  });
}

export async function listApiKeys(token: string): Promise<ListResponse<GatewayApiKey>> {
  return request<ListResponse<GatewayApiKey>>('/api/v1/api-keys', { token });
}

export async function listPlayableApiKeys(token: string): Promise<ListResponse<PlayableGatewayApiKey>> {
  return request<ListResponse<PlayableGatewayApiKey>>('/api/playground/api-keys', { token });
}

export async function createApiKey(
  token: string,
  input: { name: string; scopes?: string[]; expiresAt?: string },
): Promise<CreatedGatewayApiKey> {
  return request<CreatedGatewayApiKey>('/api/v1/api-keys', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateApiKeyScopes(token: string, apiKeyId: string, input: GatewayApiKeyScopeUpdateRequest): Promise<GatewayApiKey> {
  return request<GatewayApiKey>(`/api/v1/api-keys/${apiKeyId}/scopes`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deleteApiKey(token: string, apiKeyId: string): Promise<void> {
  await request<void>(`/api/v1/api-keys/${apiKeyId}`, {
    method: 'DELETE',
    token,
  });
}

export async function createPlatform(token: string, input: PlatformCreateInput): Promise<IntegrationPlatform> {
  return request<IntegrationPlatform>('/api/admin/platforms', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updatePlatform(token: string, platformId: string, input: PlatformCreateInput): Promise<IntegrationPlatform> {
  return request<IntegrationPlatform>(`/api/admin/platforms/${platformId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deletePlatform(token: string, platformId: string): Promise<void> {
  await request<void>(`/api/admin/platforms/${platformId}`, {
    method: 'DELETE',
    token,
  });
}

export async function createPlatformModel(
  token: string,
  platformId: string,
  input: PlatformModelBindingInput,
): Promise<PlatformModel> {
  return request<PlatformModel>(`/api/admin/platforms/${platformId}/models`, {
    body: input,
    method: 'POST',
    token,
  });
}

export async function replacePlatformModels(
  token: string,
  platformId: string,
  models: PlatformModelBindingInput[],
): Promise<ListResponse<PlatformModel>> {
  return request<ListResponse<PlatformModel>>(`/api/admin/platforms/${platformId}/models`, {
    body: { models },
    method: 'PUT',
    token,
  });
}

export async function deletePlatformModel(token: string, modelId: string): Promise<void> {
  await request<void>(`/api/admin/platform-models/${modelId}`, {
    method: 'DELETE',
    token,
  });
}

export async function createChatTask(
  token: string,
  input: { model: string; messages: Array<Record<string, unknown>>; runMode?: string; simulation?: boolean },
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
  return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/chat/completions', {
    body: input,
    headers: { 'X-Async': 'true' },
    method: 'POST',
    token,
  });
}

export async function createCompatibleChatCompletion(
  token: string,
  input: { model: string; messages: Array<Record<string, unknown>>; runMode?: string; simulation?: boolean; stream?: boolean },
): Promise<Record<string, unknown>> {
  return request<Record<string, unknown>>('/v1/chat/completions', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function createResponse(
  token: string,
  input: {
    model: string;
    input: unknown;
    instructions?: string;
    previous_response_id?: string;
    runMode?: string;
    simulation?: boolean;
    store?: boolean;
    stream?: boolean;
  },
): Promise<Record<string, unknown>> {
  return request<Record<string, unknown>>('/v1/responses', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function createEmbedding(
  token: string,
  input: { model: string; input: string | string[]; dimensions?: number; runMode?: string; simulation?: boolean },
): Promise<Record<string, unknown>> {
  return request<Record<string, unknown>>('/v1/embeddings', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function createRerank(
  token: string,
  input: { model: string; query: string; documents: string[]; top_n?: number; runMode?: string; simulation?: boolean },
): Promise<Record<string, unknown>> {
  return request<Record<string, unknown>>('/v1/reranks', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function streamChatCompletions(
  token: string,
  input: { model: string; messages: Array<Record<string, unknown>>; simulation?: boolean },
  onDelta: (delta: string) => void,
): Promise<void> {
  for await (const delta of streamChatCompletionText(token, input)) {
    onDelta(delta);
  }
}

export async function* streamChatCompletionText(
  token: string,
  input: { model: string; messages: Array<Record<string, unknown>>; simulation?: boolean },
  signal?: AbortSignal,
): AsyncGenerator<string> {
  const response = await fetch(`${API_BASE}/v1/chat/completions`, {
    body: JSON.stringify({ ...input, stream: true }),
    headers: {
      ...authorizationHeader(token),
      'Content-Type': 'application/json',
    },
    credentials: 'include',
    method: 'POST',
    signal,
  });
  if (!response.ok) {
    const body = await response.text();
    throw new GatewayApiError(parseErrorDetails(body, response.status, `Request failed: ${response.status}`));
  }
  if (!response.body) {
    return;
  }
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const events = buffer.split(/\n\n/);
    buffer = events.pop() ?? '';
    for (const eventBlock of events) {
      const event = parseSSEBlock(eventBlock);
      if (event.error) throw new GatewayApiError(event.error);
      if (event.delta) yield event.delta;
    }
  }
  if (buffer.trim()) {
    const event = parseSSEBlock(buffer);
    if (event.error) throw new GatewayApiError(event.error);
    if (event.delta) yield event.delta;
  }
}

export async function createImageGenerationTask(
  token: string,
  input: {
    model: string;
    prompt: string;
    aspect_ratio?: string;
    content?: Array<Record<string, unknown>>;
    count?: number;
    height?: number;
    image?: string | string[];
    image_url?: string | string[];
    image_urls?: string[];
    images?: string[];
    n?: number;
    quality?: string;
    referenceImage?: string | string[];
    reference_image?: string | string[];
    resolution?: string;
    runMode?: string;
    simulation?: boolean;
    size?: string;
    width?: number;
  },
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
  return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/images/generations', {
    body: input,
    headers: { 'X-Async': 'true' },
    method: 'POST',
    token,
  });
}

export async function createImageEditTask(
  token: string,
  input: {
    model: string;
    prompt: string;
    aspect_ratio?: string;
    content?: Array<Record<string, unknown>>;
    count?: number;
    height?: number;
    image?: string | string[];
    image_url?: string | string[];
    image_urls?: string[];
    images?: string[];
    mask?: string;
    n?: number;
    quality?: string;
    resolution?: string;
    runMode?: string;
    simulation?: boolean;
    size?: string;
    width?: number;
  },
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
  return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/images/edits', {
    body: input,
    headers: { 'X-Async': 'true' },
    method: 'POST',
    token,
  });
}

export type VideoGenerationContentRole =
  | 'first_frame'
  | 'last_frame'
  | 'reference_image'
  | 'reference_video'
  | 'reference_audio'
  | 'digital_human_frame'
  | 'reference'
  | 'element'
  | 'video_feature'
  | 'video_base'
  | 'shot_prompt';

export interface VideoGenerationContent {
  type: 'text' | 'image_url' | 'audio_url' | 'video_url' | 'element';
  text?: string;
  image_url?: {
    url: string;
  };
  video_url?: {
    url: string;
    mime_type?: string;
    refer_type?: 'feature' | 'base';
    keep_original_sound?: 'yes' | 'no';
  };
  audio_url?: {
    url: string;
    mime_type?: string;
  };
  role?: VideoGenerationContentRole;
  shot_index?: number;
  duration?: number;
  name?: string;
  element?: {
    system_element_id?: string;
    inline_element?: {
      name: string;
      description?: string;
      frontal_image_url: string;
      refer_images: Array<{ url: string; slot_key?: string }>;
      tags?: string[];
    };
  };
}

export interface VideoGenerationParams {
  content: VideoGenerationContent[];
  model: string;
  aspect_ratio?: string;
  resolution?: string;
  duration?: number;
  audio_list?: Array<{
    url?: string;
    audio_url?: string;
    name?: string;
  }>;
  audio?: boolean;
  framespersecond?: number;
  watermark?: boolean;
  seed?: number;
  camerafixed?: boolean;
  camera_control?: string;
  camera_control_strength?: number;
  prompt_extend?: boolean;
  size?: string;
  task_id?: string;
  conversation_id?: string;
  histories?: string;
  callback_url?: string;
  prompt_optimizer?: boolean;
  fast_pretreatment?: boolean;
  mode?: 'std' | 'pro';
  negative_prompt?: string;
  cfg_scale?: number;
  runMode?: string;
  simulation?: boolean;
}

export async function createVideoGenerationTask(
  token: string,
  input: VideoGenerationParams,
): Promise<{ task: GatewayTask; next: Record<string, string> }> {
  return request<{ task: GatewayTask; next: Record<string, string> }>('/api/v1/videos/generations', {
    body: input,
    headers: { 'X-Async': 'true' },
    method: 'POST',
    token,
  });
}

export interface GatewayFileUploadResponse extends Record<string, unknown> {
  fileUrl?: string;
  file_url?: string;
  url?: string;
}

export async function uploadFileToStorage(
  token: string,
  file: File,
  source = 'ai-gateway-playground',
): Promise<GatewayFileUploadResponse> {
  const form = new FormData();
  form.append('file', file);
  form.append('source', source);

  const response = await fetch(`${API_BASE}/v1/files/upload`, {
    body: form,
    credentials: 'include',
    headers: authorizationHeader(token),
    method: 'POST',
  });
  const body = await response.text();
  if (!response.ok) {
    throw new GatewayApiError(parseErrorDetails(body, response.status, `Request failed: ${response.status}`));
  }
  if (!body) return {};
  try {
    const parsed = JSON.parse(body) as unknown;
    return recordFromUnknown(parsed) ? (parsed as GatewayFileUploadResponse) : {};
  } catch {
    return { url: body };
  }
}

export async function estimatePricing(
  token: string,
  input: Record<string, unknown>,
  signal?: AbortSignal,
): Promise<GatewayPricingEstimate> {
  return request<GatewayPricingEstimate>('/api/v1/pricing/estimate', {
    body: input,
    method: 'POST',
    signal,
    token,
  });
}

export async function getTask(token: string, taskId: string): Promise<GatewayTask> {
  return request<GatewayTask>(`/api/workspace/tasks/${taskId}`, { token });
}

export async function getAPITask(token: string, taskId: string): Promise<GatewayTask> {
  return request<GatewayTask>(`/api/v1/tasks/${taskId}`, { token });
}

export async function listTaskParamPreprocessing(
  token: string,
  taskId: string,
): Promise<ListResponse<GatewayTaskParamPreprocessingLog>> {
  return request<ListResponse<GatewayTaskParamPreprocessingLog>>(`/api/workspace/tasks/${taskId}/param-preprocessing`, { token });
}

export async function pollTaskUntilSettled(
  token: string,
  task: GatewayTask,
  options: { intervalMs?: number; maxAttempts?: number | null; onUpdate?: (task: GatewayTask) => void } = {},
): Promise<GatewayTask> {
  let detail = task;
  const intervalMs = options.intervalMs ?? 1200;
  const maxAttempts = options.maxAttempts ?? Number.POSITIVE_INFINITY;
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
    if (!taskIsPending(detail.status)) return detail;
    try {
      detail = await getTask(token, detail.id);
      options.onUpdate?.(detail);
      if (!taskIsPending(detail.status)) return detail;
    } catch {
      // Backend restarts or short network gaps should not turn a durable task into a failed UI run.
      // Only an explicit terminal task status from the task detail endpoint settles the run.
    }
    await delay(intervalMs);
  }
  return detail;
}

export function taskIsPending(status: string) {
  return status === 'queued' || status === 'running' || status === 'submitting';
}

export async function listTasks(token: string, query: WorkspaceTaskQuery): Promise<ListResponse<GatewayTask>> {
  const search = new URLSearchParams({
    page: String(query.page),
    pageSize: String(query.pageSize),
  });
  if (query.query) search.set('q', query.query);
  if (query.modelType) search.set('modelType', query.modelType);
  if (query.createdFrom) search.set('createdFrom', query.createdFrom);
  if (query.createdTo) search.set('createdTo', query.createdTo);
  return request<ListResponse<GatewayTask>>(`/api/workspace/tasks?${search.toString()}`, { token });
}

export async function listAdminTasks(token: string, query: AdminTaskQuery): Promise<ListResponse<AdminGatewayTask>> {
  const search = new URLSearchParams({
    page: String(query.page),
    pageSize: String(query.pageSize),
  });
  if (query.query) search.set('q', query.query);
  if (query.tenantId) search.set('tenantId', query.tenantId);
  if (query.userId) search.set('userId', query.userId);
  if (query.userGroupId) search.set('userGroupId', query.userGroupId);
  if (query.status) search.set('status', query.status);
  if (query.platformId) search.set('platformId', query.platformId);
  if (query.model) search.set('model', query.model);
  if (query.modelType) search.set('modelType', query.modelType);
  if (query.runMode) search.set('runMode', query.runMode);
  if (query.billingStatus) search.set('billingStatus', query.billingStatus);
  if (query.apiKey) search.set('apiKey', query.apiKey);
  if (query.createdFrom) search.set('createdFrom', query.createdFrom);
  if (query.createdTo) search.set('createdTo', query.createdTo);
  return request<ListResponse<AdminGatewayTask>>(`/api/admin/tasks?${search.toString()}`, { token });
}

export async function getAdminTask(token: string, taskId: string, sensitive: 'masked' | 'full' = 'masked'): Promise<AdminGatewayTask> {
  return request<AdminGatewayTask>(`/api/admin/tasks/${taskId}?sensitive=${sensitive}`, { token });
}

export async function listAdminTaskParamPreprocessing(
  token: string,
  taskId: string,
  sensitive: 'masked' | 'full' = 'masked',
): Promise<ListResponse<GatewayTaskParamPreprocessingLog>> {
  return request<ListResponse<GatewayTaskParamPreprocessingLog>>(
    `/api/admin/tasks/${taskId}/param-preprocessing?sensitive=${sensitive}`,
    { token },
  );
}

export async function getWalletSummary(token: string): Promise<WalletSummaryResponse> {
  return request<WalletSummaryResponse>('/api/workspace/wallet', { token });
}

export async function listWalletTransactions(
  token: string,
  input: { query?: string; direction?: string; transactionType?: string; createdFrom?: string; createdTo?: string; page?: number; pageSize?: number } = {},
): Promise<ListResponse<GatewayWalletTransaction>> {
  const search = new URLSearchParams({
    page: String(input.page ?? 1),
    pageSize: String(input.pageSize ?? 50),
  });
  if (input.query) search.set('q', input.query);
  if (input.direction) search.set('direction', input.direction);
  if (input.transactionType) search.set('transactionType', input.transactionType);
  if (input.createdFrom) search.set('createdFrom', input.createdFrom);
  if (input.createdTo) search.set('createdTo', input.createdTo);
  return request<ListResponse<GatewayWalletTransaction>>(`/api/workspace/wallet/transactions?${search.toString()}`, { token });
}

export function resolveApiAssetUrl(src: string) {
  if (/^(https?:|data:|blob:)/i.test(src)) return src;
  return `${API_BASE}${src.startsWith('/') ? src : `/${src}`}`;
}

export async function listRateLimitWindows(token: string): Promise<ListResponse<RateLimitWindow>> {
  return request<ListResponse<RateLimitWindow>>('/api/admin/runtime/rate-limit-windows', { token });
}

export async function listModelRateLimitStatuses(token: string): Promise<ListResponse<ModelRateLimitStatus>> {
  return request<ListResponse<ModelRateLimitStatus>>('/api/admin/runtime/model-rate-limits', { token });
}

export async function restoreModelRuntimeStatus(token: string, platformModelId: string): Promise<ModelRateLimitStatus> {
  return request<ModelRateLimitStatus>(`/api/admin/runtime/model-rate-limits/${platformModelId}/restore`, {
    method: 'POST',
    token,
  });
}

export async function listBillingSettlements(
  token: string,
  input: { status?: string; action?: string; page?: number; pageSize?: number; signal?: AbortSignal } = {},
): Promise<BillingSettlementListResponse> {
  const search = new URLSearchParams({
    page: String(input.page ?? 1),
    pageSize: String(input.pageSize ?? 50),
  });
  if (input.status) search.set('status', input.status);
  if (input.action) search.set('action', input.action);
  return request<BillingSettlementListResponse>(`/api/admin/runtime/billing-settlements?${search.toString()}`, { token, signal: input.signal });
}

export async function retryBillingSettlement(token: string, settlementId: string): Promise<BillingSettlementRetryResponse> {
  const idempotencyKey = crypto.randomUUID();
  return request<BillingSettlementRetryResponse>(`/api/admin/runtime/billing-settlements/${settlementId}/retry`, {
    method: 'POST',
    token,
    headers: { 'Idempotency-Key': idempotencyKey },
  });
}

export async function getNetworkProxyConfig(token: string): Promise<GatewayNetworkProxyConfig> {
  return request<GatewayNetworkProxyConfig>('/api/admin/config/network-proxy', { token });
}

export async function listFileStorageChannels(token: string): Promise<ListResponse<FileStorageChannel>> {
  return request<ListResponse<FileStorageChannel>>('/api/admin/system/file-storage/channels', { token });
}

export async function getFileStorageSettings(token: string): Promise<FileStorageSettings> {
  return request<FileStorageSettings>('/api/admin/system/file-storage/settings', { token });
}

export async function updateFileStorageSettings(
  token: string,
  input: FileStorageSettingsUpdateRequest,
): Promise<FileStorageSettings> {
  return request<FileStorageSettings>('/api/admin/system/file-storage/settings', {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function getClientCustomizationSettings(token: string): Promise<ClientCustomizationSettings> {
  return request<ClientCustomizationSettings>('/api/admin/system/client-customization/settings', { token });
}

export async function updateClientCustomizationSettings(
  token: string,
  input: ClientCustomizationSettingsUpdateRequest,
): Promise<ClientCustomizationSettings> {
  return request<ClientCustomizationSettings>('/api/admin/system/client-customization/settings', {
    body: input,
    method: 'PATCH',
    token,
  });
}

const identityConfigurationPath = '/api/admin/system/identity';

export async function getIdentityConfiguration(token: string): Promise<IdentityConfigurationView> {
	return request<IdentityConfigurationView>(`${identityConfigurationPath}/configuration`, { token });
}

export async function startIdentityPairing(token: string, input: IdentityPairingInput): Promise<IdentityPairingExchange> {
	return identityConfigurationWrite<IdentityPairingExchange>(token, `${identityConfigurationPath}/pairings`, 'POST', 0, input, 'pair');
}

export async function getIdentityPairing(token: string, pairingId: string): Promise<IdentityPairingExchange> {
	return request<IdentityPairingExchange>(`${identityConfigurationPath}/pairings/${pairingId}`, { token });
}

export async function cancelIdentityPairing(token: string, pairingId: string, version: number): Promise<IdentityPairingExchange> {
	return identityConfigurationWrite<IdentityPairingExchange>(token, `${identityConfigurationPath}/pairings/${pairingId}/cancel`, 'POST', version, undefined, 'cancel');
}

export async function retireIdentityPairingSecurityEventConflict(token: string, pairingId: string, version: number): Promise<IdentityPairingExchange> {
	return identityConfigurationWrite<IdentityPairingExchange>(token, `${identityConfigurationPath}/pairings/${pairingId}/retire-conflicting-security-event`, 'POST', version, undefined, 'retire-ssf-conflict');
}

export async function updateIdentityRevisionPolicy(
	token: string,
	revisionId: string,
	version: number,
	input: IdentityRevisionPolicyUpdate,
): Promise<IdentityConfigurationRevision> {
	return identityConfigurationWrite<IdentityConfigurationRevision>(token, `${identityConfigurationPath}/revisions/${revisionId}`, 'PATCH', version, input, 'policy');
}

export async function validateIdentityRevision(token: string, revisionId: string, version: number): Promise<IdentityConfigurationRevision> {
	return identityConfigurationWrite<IdentityConfigurationRevision>(token, `${identityConfigurationPath}/revisions/${revisionId}/validate`, 'POST', version, undefined, 'validate');
}

export async function activateIdentityRevision(token: string, revisionId: string, version: number): Promise<IdentityConfigurationRevision> {
	return identityConfigurationWrite<IdentityConfigurationRevision>(token, `${identityConfigurationPath}/revisions/${revisionId}/activate`, 'POST', version, undefined, 'activate');
}

export async function disableIdentityConfiguration(token: string, version: number): Promise<IdentityConfigurationRevision> {
	return identityConfigurationWrite<IdentityConfigurationRevision>(token, `${identityConfigurationPath}/disable`, 'POST', version, undefined, 'disable');
}

function identityConfigurationWrite<T>(
	token: string,
	path: string,
	method: string,
	version: number,
	body: unknown,
	action: string,
): Promise<T> {
	return request<T>(path, {
		body,
		method,
		token,
		headers: {
			'Idempotency-Key': `identity-${action}-${crypto.randomUUID()}`,
			'If-Match': `W/"${version}"`,
		},
	});
}

const securityEventConnectionPath = '/api/admin/system/identity/security-events/connection';

export async function getSecurityEventConnection(token: string): Promise<SecurityEventConnectionResponse> {
  return request<SecurityEventConnectionResponse>(securityEventConnectionPath, { token });
}

export async function connectSecurityEventTransmitter(
  token: string,
  transmitterIssuer: string,
  managementClientId: string,
  managementClientSecret: string,
  version?: number,
): Promise<SecurityEventConnectionResponse> {
  const headers: Record<string, string> = { 'Idempotency-Key': `ssf-connect-${crypto.randomUUID()}` };
  if (version !== undefined) headers['If-Match'] = `W/"${version}"`;
  return request<SecurityEventConnectionResponse>(securityEventConnectionPath, {
    body: {
      transmitter_issuer: transmitterIssuer,
      management_client_id: managementClientId,
      management_client_secret: managementClientSecret,
    }, method: 'PUT', token,
    headers,
  });
}

export async function verifySecurityEventConnection(token: string, version: number): Promise<SecurityEventConnectionResponse> {
  return securityEventConnectionWrite(token, '/verify', version, 'POST', 'verify');
}

export async function rotateSecurityEventConnectionCredential(token: string, version: number): Promise<SecurityEventConnectionResponse> {
  return securityEventConnectionWrite(token, '/rotate-credential', version, 'POST', 'rotate');
}

export async function disconnectSecurityEventConnection(token: string, version: number): Promise<SecurityEventConnectionResponse> {
  return securityEventConnectionWrite(token, '', version, 'DELETE', 'disconnect');
}

function securityEventConnectionWrite(token: string, suffix: string, version: number, method: string, action: string) {
  return request<SecurityEventConnectionResponse>(securityEventConnectionPath + suffix, {
    method, token, headers: {
      'Idempotency-Key': `ssf-${action}-${crypto.randomUUID()}`,
      'If-Match': `W/"${version}"`,
    },
  });
}

export async function getPublicClientCustomization(): Promise<ClientCustomizationSettings> {
  return request<ClientCustomizationSettings>('/api/v1/public/client-customization', { auth: false });
}

export async function createFileStorageChannel(
  token: string,
  input: FileStorageChannelUpsertRequest,
): Promise<FileStorageChannel> {
  return request<FileStorageChannel>('/api/admin/system/file-storage/channels', {
    body: input,
    method: 'POST',
    token,
  });
}

export async function updateFileStorageChannel(
  token: string,
  channelId: string,
  input: FileStorageChannelUpsertRequest,
): Promise<FileStorageChannel> {
  return request<FileStorageChannel>(`/api/admin/system/file-storage/channels/${channelId}`, {
    body: input,
    method: 'PATCH',
    token,
  });
}

export async function deleteFileStorageChannel(token: string, channelId: string): Promise<void> {
  await request<void>(`/api/admin/system/file-storage/channels/${channelId}`, {
    method: 'DELETE',
    token,
  });
}

async function request<T>(
  path: string,
  options: { token?: string; auth?: boolean; method?: string; body?: unknown; headers?: Record<string, string>; signal?: AbortSignal; timeoutMs?: number } = {},
): Promise<T> {
  const headers: Record<string, string> = { ...(options.headers ?? {}) };
  if (options.auth !== false && options.token && options.token !== OIDC_BROWSER_SESSION_CREDENTIAL) {
    headers.Authorization = `Bearer ${options.token}`;
  }
  if (options.body !== undefined) {
    headers['Content-Type'] = 'application/json';
  }
  const controller = options.timeoutMs ? new AbortController() : undefined;
  const timeout = controller ? globalThis.setTimeout(() => controller.abort(), options.timeoutMs) : undefined;
  const signal = controller && options.signal
    ? AbortSignal.any([controller.signal, options.signal])
    : controller?.signal ?? options.signal;
  try {
    const response = await fetch(`${API_BASE}${path}`, {
      method: options.method ?? 'GET',
      headers,
      body: options.body === undefined ? undefined : JSON.stringify(options.body),
      credentials: 'include',
      signal,
    });
    if (!response.ok) {
      const body = await response.text();
      throw new GatewayApiError(parseErrorDetails(body, response.status, `Request failed: ${response.status}`));
    }
    if (response.status === 204) {
      return undefined as T;
    }
    return response.json() as Promise<T>;
  } catch (error) {
    if (controller?.signal.aborted) {
      throw new GatewayApiError('登录请求超时，请稍后重试');
    }
    throw error;
  } finally {
    if (timeout !== undefined) globalThis.clearTimeout(timeout);
  }
}

function authorizationHeader(token: string): Record<string, string> {
  if (!token || token === OIDC_BROWSER_SESSION_CREDENTIAL) return {};
  return { Authorization: `Bearer ${token}` };
}

function delay(ms: number) {
  return new Promise((resolve) => window.setTimeout(resolve, ms));
}

function parseErrorMessage(body: string) {
  return formatGatewayErrorDetails(parseErrorDetails(body));
}

function parseErrorDetails(body: string, status?: number, fallback = ''): GatewayErrorDetails {
  if (!body) {
    return { message: fallback, status };
  }
  try {
    const parsed = JSON.parse(body) as unknown;
    return errorDetailsFromParsed(parsed, status, fallback || body);
  } catch {
    return { message: body || fallback, status };
  }
}

function parseSSEBlock(block: string): { delta: string; error?: GatewayErrorDetails } {
  const eventName = block
    .split(/\n/)
    .find((line) => line.startsWith('event:'))
    ?.replace(/^event:\s?/, '')
    .trim();
  const data = block
    .split(/\n/)
    .filter((line) => line.startsWith('data:'))
    .map((line) => line.replace(/^data:\s?/, ''))
    .join('\n')
    .trim();
  if (!data || data === '[DONE]') return { delta: '' };
  try {
    const parsed = JSON.parse(data) as {
      choices?: Array<{ delta?: { content?: string }; message?: { content?: string } }>;
      delta?: string;
      error?: unknown;
      output_text?: string;
    };
    if (eventName === 'error' || parsed.error) {
      return { delta: '', error: errorDetailsFromParsed(parsed, undefined, data) };
    }
    return { delta: parsed.choices?.[0]?.delta?.content ?? parsed.delta ?? parsed.output_text ?? '' };
  } catch {
    if (eventName === 'error') return { delta: '', error: { message: data } };
    return { delta: data };
  }
}

function errorDetailsFromParsed(parsed: unknown, status?: number, fallback = ''): GatewayErrorDetails {
  const root = recordFromUnknown(parsed);
  if (!root) return { message: fallback, status };
  const error = recordFromUnknown(root.error);
  const message = firstString(
    error?.message,
    error?.error,
    root.message,
    root.errorMessage,
    fallback,
  );
  return {
    code: firstString(error?.code, error?.type, root.code, root.errorCode),
    message: message || fallback,
    requestId: firstString(error?.requestId, error?.request_id, root.requestId, root.request_id),
    status: numberFromUnknown(error?.status) ?? numberFromUnknown(root.status) ?? status,
    taskId: firstString(error?.taskId, error?.task_id, root.taskId, root.task_id),
  };
}

function formatGatewayErrorDetails(details: GatewayErrorDetails) {
  const message = gatewayErrorMessage(details);
  const meta = [
    details.code ? `错误码: ${details.code}` : '',
    details.status ? `状态: ${details.status}` : '',
    details.requestId ? `RequestID: ${details.requestId}` : '',
    details.taskId ? `TaskID: ${details.taskId}` : '',
  ].filter(Boolean);
  return meta.length ? `${message}（${meta.join('，')}）` : message;
}

const gatewayProvisioningErrorMessages: Record<string, string> = {
  GATEWAY_USER_NOT_PROVISIONED: '该账号尚未开通 EasyAI Gateway',
  GATEWAY_USER_DISABLED: '该 Gateway 账号已停用，请联系管理员',
  GATEWAY_TENANT_UNAVAILABLE: 'Gateway 租户尚未就绪，请联系管理员',
  GATEWAY_USER_PROVISIONING_FAILED: 'Gateway 账号初始化失败，请稍后重试',
  OIDC_BROWSER_SESSION_DISABLED: 'Gateway 浏览器会话尚未启用',
  OIDC_SESSION_INVALID: '统一认证会话无效，请重新登录',
  OIDC_SESSION_EXPIRED: '统一认证会话已过期，请重新登录',
  OIDC_SESSION_REFRESH_UNAVAILABLE: '认证中心暂时不可用，请稍后重试',
  OIDC_SESSION_STORE_UNAVAILABLE: '登录会话存储暂时不可用，请稍后重试',
  OIDC_SESSION_CSRF_REJECTED: '登录会话来源校验失败，请刷新后重试',
  IDENTITY_PAIRING_IN_PROGRESS: '请先完成或放弃当前统一认证配对',
  IDENTITY_PAIRING_NOT_CANCELLABLE: '当前统一认证配置不能放弃',
  IDENTITY_PAIRING_CONFLICT_NOT_RESOLVABLE: '当前配对状态已变化，请刷新后重试',
  IDENTITY_VERSION_CONFLICT: '统一认证状态已变化，请刷新后重试',
};

export function gatewayErrorMessage(details: GatewayErrorDetails) {
  return (details.code && gatewayProvisioningErrorMessages[details.code]) || details.message || '请求失败';
}

function recordFromUnknown(value: unknown): Record<string, unknown> | undefined {
  if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
  return value as Record<string, unknown>;
}

function firstString(...values: unknown[]) {
  return values.map((value) => typeof value === 'string' ? value.trim() : '').find(Boolean) ?? '';
}

function numberFromUnknown(value: unknown) {
  if (typeof value === 'number' && Number.isFinite(value)) return value;
  if (typeof value === 'string' && value.trim()) {
    const parsed = Number(value);
    if (Number.isFinite(parsed)) return parsed;
  }
  return undefined;
}
